Commit 3c3fed88 authored by Edric Li's avatar Edric Li
Browse files

feat(backend): add user custom attributes system

Add a flexible user attribute system that allows admins to define
custom fields for users (text, textarea, number, email, url, date,
select, multi_select types).

- Add Ent schemas for UserAttributeDefinition and UserAttributeValue
- Add service layer with validation logic
- Add repository layer with batch operations support
- Add admin API endpoints for CRUD and reorder operations
- Add batch API for loading attribute values for multiple users
- Add database migration (018_user_attributes.sql)

🤖 Generated with [Claude Code](https://claude.com/claude-code

)
Co-Authored-By: default avatarClaude Opus 4.5 <noreply@anthropic.com>
parent 7331220e
...@@ -114,15 +114,19 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) { ...@@ -114,15 +114,19 @@ func initializeApplication(buildInfo handler.BuildInfo) (*Application, error) {
gitHubReleaseClient := repository.NewGitHubReleaseClient() gitHubReleaseClient := repository.NewGitHubReleaseClient()
serviceBuildInfo := provideServiceBuildInfo(buildInfo) serviceBuildInfo := provideServiceBuildInfo(buildInfo)
updateService := service.ProvideUpdateService(updateCache, gitHubReleaseClient, serviceBuildInfo) updateService := service.ProvideUpdateService(updateCache, gitHubReleaseClient, serviceBuildInfo)
systemHandler := handler.ProvideSystemHandler(updateService)
adminSubscriptionHandler := admin.NewSubscriptionHandler(subscriptionService)
adminUsageHandler := admin.NewUsageHandler(usageService, apiKeyService, adminService)
userAttributeDefinitionRepository := repository.NewUserAttributeDefinitionRepository(client)
userAttributeValueRepository := repository.NewUserAttributeValueRepository(client, db)
userAttributeService := service.NewUserAttributeService(userAttributeDefinitionRepository, userAttributeValueRepository)
userAttributeHandler := admin.NewUserAttributeHandler(userAttributeService)
adminHandlers := handler.ProvideAdminHandlers(dashboardHandler, 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 {
return nil, err return nil, err
} }
systemHandler := handler.ProvideSystemHandler(updateService)
adminSubscriptionHandler := admin.NewSubscriptionHandler(subscriptionService)
adminUsageHandler := admin.NewUsageHandler(usageService, apiKeyService, adminService)
adminHandlers := handler.ProvideAdminHandlers(dashboardHandler, adminUserHandler, groupHandler, accountHandler, oAuthHandler, openAIOAuthHandler, geminiOAuthHandler, antigravityOAuthHandler, proxyHandler, adminRedeemHandler, settingHandler, systemHandler, adminSubscriptionHandler, adminUsageHandler)
billingService := service.NewBillingService(configConfig, pricingService) billingService := service.NewBillingService(configConfig, pricingService)
identityCache := repository.NewIdentityCache(redisClient) identityCache := repository.NewIdentityCache(redisClient)
identityService := service.NewIdentityService(identityCache) identityService := service.NewIdentityService(identityCache)
......
This diff is collapsed.
...@@ -22,6 +22,8 @@ import ( ...@@ -22,6 +22,8 @@ import (
"github.com/Wei-Shaw/sub2api/ent/usagelog" "github.com/Wei-Shaw/sub2api/ent/usagelog"
"github.com/Wei-Shaw/sub2api/ent/user" "github.com/Wei-Shaw/sub2api/ent/user"
"github.com/Wei-Shaw/sub2api/ent/userallowedgroup" "github.com/Wei-Shaw/sub2api/ent/userallowedgroup"
"github.com/Wei-Shaw/sub2api/ent/userattributedefinition"
"github.com/Wei-Shaw/sub2api/ent/userattributevalue"
"github.com/Wei-Shaw/sub2api/ent/usersubscription" "github.com/Wei-Shaw/sub2api/ent/usersubscription"
) )
...@@ -83,17 +85,19 @@ var ( ...@@ -83,17 +85,19 @@ var (
func checkColumn(t, c string) error { func checkColumn(t, c string) error {
initCheck.Do(func() { initCheck.Do(func() {
columnCheck = sql.NewColumnCheck(map[string]func(string) bool{ columnCheck = sql.NewColumnCheck(map[string]func(string) bool{
account.Table: account.ValidColumn, account.Table: account.ValidColumn,
accountgroup.Table: accountgroup.ValidColumn, accountgroup.Table: accountgroup.ValidColumn,
apikey.Table: apikey.ValidColumn, apikey.Table: apikey.ValidColumn,
group.Table: group.ValidColumn, group.Table: group.ValidColumn,
proxy.Table: proxy.ValidColumn, proxy.Table: proxy.ValidColumn,
redeemcode.Table: redeemcode.ValidColumn, redeemcode.Table: redeemcode.ValidColumn,
setting.Table: setting.ValidColumn, setting.Table: setting.ValidColumn,
usagelog.Table: usagelog.ValidColumn, usagelog.Table: usagelog.ValidColumn,
user.Table: user.ValidColumn, user.Table: user.ValidColumn,
userallowedgroup.Table: userallowedgroup.ValidColumn, userallowedgroup.Table: userallowedgroup.ValidColumn,
usersubscription.Table: usersubscription.ValidColumn, userattributedefinition.Table: userattributedefinition.ValidColumn,
userattributevalue.Table: userattributevalue.ValidColumn,
usersubscription.Table: usersubscription.ValidColumn,
}) })
}) })
return columnCheck(t, c) return columnCheck(t, c)
......
...@@ -129,6 +129,30 @@ func (f UserAllowedGroupFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.V ...@@ -129,6 +129,30 @@ func (f UserAllowedGroupFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.V
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.UserAllowedGroupMutation", m) return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.UserAllowedGroupMutation", m)
} }
// The UserAttributeDefinitionFunc type is an adapter to allow the use of ordinary
// function as UserAttributeDefinition mutator.
type UserAttributeDefinitionFunc func(context.Context, *ent.UserAttributeDefinitionMutation) (ent.Value, error)
// Mutate calls f(ctx, m).
func (f UserAttributeDefinitionFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
if mv, ok := m.(*ent.UserAttributeDefinitionMutation); ok {
return f(ctx, mv)
}
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.UserAttributeDefinitionMutation", m)
}
// The UserAttributeValueFunc type is an adapter to allow the use of ordinary
// function as UserAttributeValue mutator.
type UserAttributeValueFunc func(context.Context, *ent.UserAttributeValueMutation) (ent.Value, error)
// Mutate calls f(ctx, m).
func (f UserAttributeValueFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) {
if mv, ok := m.(*ent.UserAttributeValueMutation); ok {
return f(ctx, mv)
}
return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.UserAttributeValueMutation", m)
}
// The UserSubscriptionFunc type is an adapter to allow the use of ordinary // The UserSubscriptionFunc type is an adapter to allow the use of ordinary
// function as UserSubscription mutator. // function as UserSubscription mutator.
type UserSubscriptionFunc func(context.Context, *ent.UserSubscriptionMutation) (ent.Value, error) type UserSubscriptionFunc func(context.Context, *ent.UserSubscriptionMutation) (ent.Value, error)
......
...@@ -19,6 +19,8 @@ import ( ...@@ -19,6 +19,8 @@ import (
"github.com/Wei-Shaw/sub2api/ent/usagelog" "github.com/Wei-Shaw/sub2api/ent/usagelog"
"github.com/Wei-Shaw/sub2api/ent/user" "github.com/Wei-Shaw/sub2api/ent/user"
"github.com/Wei-Shaw/sub2api/ent/userallowedgroup" "github.com/Wei-Shaw/sub2api/ent/userallowedgroup"
"github.com/Wei-Shaw/sub2api/ent/userattributedefinition"
"github.com/Wei-Shaw/sub2api/ent/userattributevalue"
"github.com/Wei-Shaw/sub2api/ent/usersubscription" "github.com/Wei-Shaw/sub2api/ent/usersubscription"
) )
...@@ -348,6 +350,60 @@ func (f TraverseUserAllowedGroup) Traverse(ctx context.Context, q ent.Query) err ...@@ -348,6 +350,60 @@ func (f TraverseUserAllowedGroup) Traverse(ctx context.Context, q ent.Query) err
return fmt.Errorf("unexpected query type %T. expect *ent.UserAllowedGroupQuery", q) return fmt.Errorf("unexpected query type %T. expect *ent.UserAllowedGroupQuery", q)
} }
// The UserAttributeDefinitionFunc type is an adapter to allow the use of ordinary function as a Querier.
type UserAttributeDefinitionFunc func(context.Context, *ent.UserAttributeDefinitionQuery) (ent.Value, error)
// Query calls f(ctx, q).
func (f UserAttributeDefinitionFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
if q, ok := q.(*ent.UserAttributeDefinitionQuery); ok {
return f(ctx, q)
}
return nil, fmt.Errorf("unexpected query type %T. expect *ent.UserAttributeDefinitionQuery", q)
}
// The TraverseUserAttributeDefinition type is an adapter to allow the use of ordinary function as Traverser.
type TraverseUserAttributeDefinition func(context.Context, *ent.UserAttributeDefinitionQuery) error
// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
func (f TraverseUserAttributeDefinition) Intercept(next ent.Querier) ent.Querier {
return next
}
// Traverse calls f(ctx, q).
func (f TraverseUserAttributeDefinition) Traverse(ctx context.Context, q ent.Query) error {
if q, ok := q.(*ent.UserAttributeDefinitionQuery); ok {
return f(ctx, q)
}
return fmt.Errorf("unexpected query type %T. expect *ent.UserAttributeDefinitionQuery", q)
}
// The UserAttributeValueFunc type is an adapter to allow the use of ordinary function as a Querier.
type UserAttributeValueFunc func(context.Context, *ent.UserAttributeValueQuery) (ent.Value, error)
// Query calls f(ctx, q).
func (f UserAttributeValueFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) {
if q, ok := q.(*ent.UserAttributeValueQuery); ok {
return f(ctx, q)
}
return nil, fmt.Errorf("unexpected query type %T. expect *ent.UserAttributeValueQuery", q)
}
// The TraverseUserAttributeValue type is an adapter to allow the use of ordinary function as Traverser.
type TraverseUserAttributeValue func(context.Context, *ent.UserAttributeValueQuery) error
// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline.
func (f TraverseUserAttributeValue) Intercept(next ent.Querier) ent.Querier {
return next
}
// Traverse calls f(ctx, q).
func (f TraverseUserAttributeValue) Traverse(ctx context.Context, q ent.Query) error {
if q, ok := q.(*ent.UserAttributeValueQuery); ok {
return f(ctx, q)
}
return fmt.Errorf("unexpected query type %T. expect *ent.UserAttributeValueQuery", q)
}
// The UserSubscriptionFunc type is an adapter to allow the use of ordinary function as a Querier. // The UserSubscriptionFunc type is an adapter to allow the use of ordinary function as a Querier.
type UserSubscriptionFunc func(context.Context, *ent.UserSubscriptionQuery) (ent.Value, error) type UserSubscriptionFunc func(context.Context, *ent.UserSubscriptionQuery) (ent.Value, error)
...@@ -398,6 +454,10 @@ func NewQuery(q ent.Query) (Query, error) { ...@@ -398,6 +454,10 @@ func NewQuery(q ent.Query) (Query, error) {
return &query[*ent.UserQuery, predicate.User, user.OrderOption]{typ: ent.TypeUser, tq: q}, nil return &query[*ent.UserQuery, predicate.User, user.OrderOption]{typ: ent.TypeUser, tq: q}, nil
case *ent.UserAllowedGroupQuery: case *ent.UserAllowedGroupQuery:
return &query[*ent.UserAllowedGroupQuery, predicate.UserAllowedGroup, userallowedgroup.OrderOption]{typ: ent.TypeUserAllowedGroup, tq: q}, nil return &query[*ent.UserAllowedGroupQuery, predicate.UserAllowedGroup, userallowedgroup.OrderOption]{typ: ent.TypeUserAllowedGroup, tq: q}, nil
case *ent.UserAttributeDefinitionQuery:
return &query[*ent.UserAttributeDefinitionQuery, predicate.UserAttributeDefinition, userattributedefinition.OrderOption]{typ: ent.TypeUserAttributeDefinition, tq: q}, nil
case *ent.UserAttributeValueQuery:
return &query[*ent.UserAttributeValueQuery, predicate.UserAttributeValue, userattributevalue.OrderOption]{typ: ent.TypeUserAttributeValue, tq: q}, nil
case *ent.UserSubscriptionQuery: case *ent.UserSubscriptionQuery:
return &query[*ent.UserSubscriptionQuery, predicate.UserSubscription, usersubscription.OrderOption]{typ: ent.TypeUserSubscription, tq: q}, nil return &query[*ent.UserSubscriptionQuery, predicate.UserSubscription, usersubscription.OrderOption]{typ: ent.TypeUserSubscription, tq: q}, nil
default: default:
......
...@@ -477,7 +477,6 @@ var ( ...@@ -477,7 +477,6 @@ var (
{Name: "concurrency", Type: field.TypeInt, Default: 5}, {Name: "concurrency", Type: field.TypeInt, Default: 5},
{Name: "status", Type: field.TypeString, Size: 20, Default: "active"}, {Name: "status", Type: field.TypeString, Size: 20, Default: "active"},
{Name: "username", Type: field.TypeString, Size: 100, Default: ""}, {Name: "username", Type: field.TypeString, Size: 100, Default: ""},
{Name: "wechat", Type: field.TypeString, Size: 100, Default: ""},
{Name: "notes", Type: field.TypeString, Default: "", SchemaType: map[string]string{"postgres": "text"}}, {Name: "notes", Type: field.TypeString, Default: "", SchemaType: map[string]string{"postgres": "text"}},
} }
// UsersTable holds the schema information for the "users" table. // UsersTable holds the schema information for the "users" table.
...@@ -531,6 +530,92 @@ var ( ...@@ -531,6 +530,92 @@ var (
}, },
}, },
} }
// UserAttributeDefinitionsColumns holds the columns for the "user_attribute_definitions" table.
UserAttributeDefinitionsColumns = []*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, Size: 100},
{Name: "name", Type: field.TypeString, Size: 255},
{Name: "description", Type: field.TypeString, Default: "", SchemaType: map[string]string{"postgres": "text"}},
{Name: "type", Type: field.TypeString, Size: 20},
{Name: "options", Type: field.TypeJSON, SchemaType: map[string]string{"postgres": "jsonb"}},
{Name: "required", Type: field.TypeBool, Default: false},
{Name: "validation", Type: field.TypeJSON, SchemaType: map[string]string{"postgres": "jsonb"}},
{Name: "placeholder", Type: field.TypeString, Size: 255, Default: ""},
{Name: "display_order", Type: field.TypeInt, Default: 0},
{Name: "enabled", Type: field.TypeBool, Default: true},
}
// UserAttributeDefinitionsTable holds the schema information for the "user_attribute_definitions" table.
UserAttributeDefinitionsTable = &schema.Table{
Name: "user_attribute_definitions",
Columns: UserAttributeDefinitionsColumns,
PrimaryKey: []*schema.Column{UserAttributeDefinitionsColumns[0]},
Indexes: []*schema.Index{
{
Name: "userattributedefinition_key",
Unique: false,
Columns: []*schema.Column{UserAttributeDefinitionsColumns[4]},
},
{
Name: "userattributedefinition_enabled",
Unique: false,
Columns: []*schema.Column{UserAttributeDefinitionsColumns[13]},
},
{
Name: "userattributedefinition_display_order",
Unique: false,
Columns: []*schema.Column{UserAttributeDefinitionsColumns[12]},
},
{
Name: "userattributedefinition_deleted_at",
Unique: false,
Columns: []*schema.Column{UserAttributeDefinitionsColumns[3]},
},
},
}
// UserAttributeValuesColumns holds the columns for the "user_attribute_values" table.
UserAttributeValuesColumns = []*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: "value", Type: field.TypeString, Size: 2147483647, Default: ""},
{Name: "user_id", Type: field.TypeInt64},
{Name: "attribute_id", Type: field.TypeInt64},
}
// UserAttributeValuesTable holds the schema information for the "user_attribute_values" table.
UserAttributeValuesTable = &schema.Table{
Name: "user_attribute_values",
Columns: UserAttributeValuesColumns,
PrimaryKey: []*schema.Column{UserAttributeValuesColumns[0]},
ForeignKeys: []*schema.ForeignKey{
{
Symbol: "user_attribute_values_users_attribute_values",
Columns: []*schema.Column{UserAttributeValuesColumns[4]},
RefColumns: []*schema.Column{UsersColumns[0]},
OnDelete: schema.NoAction,
},
{
Symbol: "user_attribute_values_user_attribute_definitions_values",
Columns: []*schema.Column{UserAttributeValuesColumns[5]},
RefColumns: []*schema.Column{UserAttributeDefinitionsColumns[0]},
OnDelete: schema.NoAction,
},
},
Indexes: []*schema.Index{
{
Name: "userattributevalue_user_id_attribute_id",
Unique: true,
Columns: []*schema.Column{UserAttributeValuesColumns[4], UserAttributeValuesColumns[5]},
},
{
Name: "userattributevalue_attribute_id",
Unique: false,
Columns: []*schema.Column{UserAttributeValuesColumns[5]},
},
},
}
// UserSubscriptionsColumns holds the columns for the "user_subscriptions" table. // UserSubscriptionsColumns holds the columns for the "user_subscriptions" table.
UserSubscriptionsColumns = []*schema.Column{ UserSubscriptionsColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt64, Increment: true}, {Name: "id", Type: field.TypeInt64, Increment: true},
...@@ -627,6 +712,8 @@ var ( ...@@ -627,6 +712,8 @@ var (
UsageLogsTable, UsageLogsTable,
UsersTable, UsersTable,
UserAllowedGroupsTable, UserAllowedGroupsTable,
UserAttributeDefinitionsTable,
UserAttributeValuesTable,
UserSubscriptionsTable, UserSubscriptionsTable,
} }
) )
...@@ -676,6 +763,14 @@ func init() { ...@@ -676,6 +763,14 @@ func init() {
UserAllowedGroupsTable.Annotation = &entsql.Annotation{ UserAllowedGroupsTable.Annotation = &entsql.Annotation{
Table: "user_allowed_groups", Table: "user_allowed_groups",
} }
UserAttributeDefinitionsTable.Annotation = &entsql.Annotation{
Table: "user_attribute_definitions",
}
UserAttributeValuesTable.ForeignKeys[0].RefTable = UsersTable
UserAttributeValuesTable.ForeignKeys[1].RefTable = UserAttributeDefinitionsTable
UserAttributeValuesTable.Annotation = &entsql.Annotation{
Table: "user_attribute_values",
}
UserSubscriptionsTable.ForeignKeys[0].RefTable = GroupsTable UserSubscriptionsTable.ForeignKeys[0].RefTable = GroupsTable
UserSubscriptionsTable.ForeignKeys[1].RefTable = UsersTable UserSubscriptionsTable.ForeignKeys[1].RefTable = UsersTable
UserSubscriptionsTable.ForeignKeys[2].RefTable = UsersTable UserSubscriptionsTable.ForeignKeys[2].RefTable = UsersTable
......
This diff is collapsed.
...@@ -36,5 +36,11 @@ type User func(*sql.Selector) ...@@ -36,5 +36,11 @@ type User func(*sql.Selector)
// UserAllowedGroup is the predicate function for userallowedgroup builders. // UserAllowedGroup is the predicate function for userallowedgroup builders.
type UserAllowedGroup func(*sql.Selector) type UserAllowedGroup func(*sql.Selector)
// UserAttributeDefinition is the predicate function for userattributedefinition builders.
type UserAttributeDefinition func(*sql.Selector)
// UserAttributeValue is the predicate function for userattributevalue builders.
type UserAttributeValue func(*sql.Selector)
// UserSubscription is the predicate function for usersubscription builders. // UserSubscription is the predicate function for usersubscription builders.
type UserSubscription func(*sql.Selector) type UserSubscription func(*sql.Selector)
...@@ -16,6 +16,8 @@ import ( ...@@ -16,6 +16,8 @@ import (
"github.com/Wei-Shaw/sub2api/ent/usagelog" "github.com/Wei-Shaw/sub2api/ent/usagelog"
"github.com/Wei-Shaw/sub2api/ent/user" "github.com/Wei-Shaw/sub2api/ent/user"
"github.com/Wei-Shaw/sub2api/ent/userallowedgroup" "github.com/Wei-Shaw/sub2api/ent/userallowedgroup"
"github.com/Wei-Shaw/sub2api/ent/userattributedefinition"
"github.com/Wei-Shaw/sub2api/ent/userattributevalue"
"github.com/Wei-Shaw/sub2api/ent/usersubscription" "github.com/Wei-Shaw/sub2api/ent/usersubscription"
) )
...@@ -604,14 +606,8 @@ func init() { ...@@ -604,14 +606,8 @@ func init() {
user.DefaultUsername = userDescUsername.Default.(string) user.DefaultUsername = userDescUsername.Default.(string)
// user.UsernameValidator is a validator for the "username" field. It is called by the builders before save. // user.UsernameValidator is a validator for the "username" field. It is called by the builders before save.
user.UsernameValidator = userDescUsername.Validators[0].(func(string) error) user.UsernameValidator = userDescUsername.Validators[0].(func(string) error)
// userDescWechat is the schema descriptor for wechat field.
userDescWechat := userFields[7].Descriptor()
// user.DefaultWechat holds the default value on creation for the wechat field.
user.DefaultWechat = userDescWechat.Default.(string)
// user.WechatValidator is a validator for the "wechat" field. It is called by the builders before save.
user.WechatValidator = userDescWechat.Validators[0].(func(string) error)
// userDescNotes is the schema descriptor for notes field. // userDescNotes is the schema descriptor for notes field.
userDescNotes := userFields[8].Descriptor() userDescNotes := userFields[7].Descriptor()
// user.DefaultNotes holds the default value on creation for the notes field. // user.DefaultNotes holds the default value on creation for the notes field.
user.DefaultNotes = userDescNotes.Default.(string) user.DefaultNotes = userDescNotes.Default.(string)
userallowedgroupFields := schema.UserAllowedGroup{}.Fields() userallowedgroupFields := schema.UserAllowedGroup{}.Fields()
...@@ -620,6 +616,128 @@ func init() { ...@@ -620,6 +616,128 @@ func init() {
userallowedgroupDescCreatedAt := userallowedgroupFields[2].Descriptor() userallowedgroupDescCreatedAt := userallowedgroupFields[2].Descriptor()
// userallowedgroup.DefaultCreatedAt holds the default value on creation for the created_at field. // userallowedgroup.DefaultCreatedAt holds the default value on creation for the created_at field.
userallowedgroup.DefaultCreatedAt = userallowedgroupDescCreatedAt.Default.(func() time.Time) userallowedgroup.DefaultCreatedAt = userallowedgroupDescCreatedAt.Default.(func() time.Time)
userattributedefinitionMixin := schema.UserAttributeDefinition{}.Mixin()
userattributedefinitionMixinHooks1 := userattributedefinitionMixin[1].Hooks()
userattributedefinition.Hooks[0] = userattributedefinitionMixinHooks1[0]
userattributedefinitionMixinInters1 := userattributedefinitionMixin[1].Interceptors()
userattributedefinition.Interceptors[0] = userattributedefinitionMixinInters1[0]
userattributedefinitionMixinFields0 := userattributedefinitionMixin[0].Fields()
_ = userattributedefinitionMixinFields0
userattributedefinitionFields := schema.UserAttributeDefinition{}.Fields()
_ = userattributedefinitionFields
// userattributedefinitionDescCreatedAt is the schema descriptor for created_at field.
userattributedefinitionDescCreatedAt := userattributedefinitionMixinFields0[0].Descriptor()
// userattributedefinition.DefaultCreatedAt holds the default value on creation for the created_at field.
userattributedefinition.DefaultCreatedAt = userattributedefinitionDescCreatedAt.Default.(func() time.Time)
// userattributedefinitionDescUpdatedAt is the schema descriptor for updated_at field.
userattributedefinitionDescUpdatedAt := userattributedefinitionMixinFields0[1].Descriptor()
// userattributedefinition.DefaultUpdatedAt holds the default value on creation for the updated_at field.
userattributedefinition.DefaultUpdatedAt = userattributedefinitionDescUpdatedAt.Default.(func() time.Time)
// userattributedefinition.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
userattributedefinition.UpdateDefaultUpdatedAt = userattributedefinitionDescUpdatedAt.UpdateDefault.(func() time.Time)
// userattributedefinitionDescKey is the schema descriptor for key field.
userattributedefinitionDescKey := userattributedefinitionFields[0].Descriptor()
// userattributedefinition.KeyValidator is a validator for the "key" field. It is called by the builders before save.
userattributedefinition.KeyValidator = func() func(string) error {
validators := userattributedefinitionDescKey.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
}
}()
// userattributedefinitionDescName is the schema descriptor for name field.
userattributedefinitionDescName := userattributedefinitionFields[1].Descriptor()
// userattributedefinition.NameValidator is a validator for the "name" field. It is called by the builders before save.
userattributedefinition.NameValidator = func() func(string) error {
validators := userattributedefinitionDescName.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
}
}()
// userattributedefinitionDescDescription is the schema descriptor for description field.
userattributedefinitionDescDescription := userattributedefinitionFields[2].Descriptor()
// userattributedefinition.DefaultDescription holds the default value on creation for the description field.
userattributedefinition.DefaultDescription = userattributedefinitionDescDescription.Default.(string)
// userattributedefinitionDescType is the schema descriptor for type field.
userattributedefinitionDescType := userattributedefinitionFields[3].Descriptor()
// userattributedefinition.TypeValidator is a validator for the "type" field. It is called by the builders before save.
userattributedefinition.TypeValidator = func() func(string) error {
validators := userattributedefinitionDescType.Validators
fns := [...]func(string) error{
validators[0].(func(string) error),
validators[1].(func(string) error),
}
return func(_type string) error {
for _, fn := range fns {
if err := fn(_type); err != nil {
return err
}
}
return nil
}
}()
// userattributedefinitionDescOptions is the schema descriptor for options field.
userattributedefinitionDescOptions := userattributedefinitionFields[4].Descriptor()
// userattributedefinition.DefaultOptions holds the default value on creation for the options field.
userattributedefinition.DefaultOptions = userattributedefinitionDescOptions.Default.([]map[string]interface{})
// userattributedefinitionDescRequired is the schema descriptor for required field.
userattributedefinitionDescRequired := userattributedefinitionFields[5].Descriptor()
// userattributedefinition.DefaultRequired holds the default value on creation for the required field.
userattributedefinition.DefaultRequired = userattributedefinitionDescRequired.Default.(bool)
// userattributedefinitionDescValidation is the schema descriptor for validation field.
userattributedefinitionDescValidation := userattributedefinitionFields[6].Descriptor()
// userattributedefinition.DefaultValidation holds the default value on creation for the validation field.
userattributedefinition.DefaultValidation = userattributedefinitionDescValidation.Default.(map[string]interface{})
// userattributedefinitionDescPlaceholder is the schema descriptor for placeholder field.
userattributedefinitionDescPlaceholder := userattributedefinitionFields[7].Descriptor()
// userattributedefinition.DefaultPlaceholder holds the default value on creation for the placeholder field.
userattributedefinition.DefaultPlaceholder = userattributedefinitionDescPlaceholder.Default.(string)
// userattributedefinition.PlaceholderValidator is a validator for the "placeholder" field. It is called by the builders before save.
userattributedefinition.PlaceholderValidator = userattributedefinitionDescPlaceholder.Validators[0].(func(string) error)
// userattributedefinitionDescDisplayOrder is the schema descriptor for display_order field.
userattributedefinitionDescDisplayOrder := userattributedefinitionFields[8].Descriptor()
// userattributedefinition.DefaultDisplayOrder holds the default value on creation for the display_order field.
userattributedefinition.DefaultDisplayOrder = userattributedefinitionDescDisplayOrder.Default.(int)
// userattributedefinitionDescEnabled is the schema descriptor for enabled field.
userattributedefinitionDescEnabled := userattributedefinitionFields[9].Descriptor()
// userattributedefinition.DefaultEnabled holds the default value on creation for the enabled field.
userattributedefinition.DefaultEnabled = userattributedefinitionDescEnabled.Default.(bool)
userattributevalueMixin := schema.UserAttributeValue{}.Mixin()
userattributevalueMixinFields0 := userattributevalueMixin[0].Fields()
_ = userattributevalueMixinFields0
userattributevalueFields := schema.UserAttributeValue{}.Fields()
_ = userattributevalueFields
// userattributevalueDescCreatedAt is the schema descriptor for created_at field.
userattributevalueDescCreatedAt := userattributevalueMixinFields0[0].Descriptor()
// userattributevalue.DefaultCreatedAt holds the default value on creation for the created_at field.
userattributevalue.DefaultCreatedAt = userattributevalueDescCreatedAt.Default.(func() time.Time)
// userattributevalueDescUpdatedAt is the schema descriptor for updated_at field.
userattributevalueDescUpdatedAt := userattributevalueMixinFields0[1].Descriptor()
// userattributevalue.DefaultUpdatedAt holds the default value on creation for the updated_at field.
userattributevalue.DefaultUpdatedAt = userattributevalueDescUpdatedAt.Default.(func() time.Time)
// userattributevalue.UpdateDefaultUpdatedAt holds the default value on update for the updated_at field.
userattributevalue.UpdateDefaultUpdatedAt = userattributevalueDescUpdatedAt.UpdateDefault.(func() time.Time)
// userattributevalueDescValue is the schema descriptor for value field.
userattributevalueDescValue := userattributevalueFields[2].Descriptor()
// userattributevalue.DefaultValue holds the default value on creation for the value field.
userattributevalue.DefaultValue = userattributevalueDescValue.Default.(string)
usersubscriptionMixin := schema.UserSubscription{}.Mixin() usersubscriptionMixin := schema.UserSubscription{}.Mixin()
usersubscriptionMixinHooks1 := usersubscriptionMixin[1].Hooks() usersubscriptionMixinHooks1 := usersubscriptionMixin[1].Hooks()
usersubscription.Hooks[0] = usersubscriptionMixinHooks1[0] usersubscription.Hooks[0] = usersubscriptionMixinHooks1[0]
......
package schema
import (
"github.com/Wei-Shaw/sub2api/ent/schema/mixins"
"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"
)
// UserAttributeDefinition holds the schema definition for custom user attributes.
//
// This entity defines the metadata for user attributes, such as:
// - Attribute key (unique identifier like "company_name")
// - Display name shown in forms
// - Field type (text, number, select, etc.)
// - Validation rules
// - Whether the field is required or enabled
type UserAttributeDefinition struct {
ent.Schema
}
func (UserAttributeDefinition) Annotations() []schema.Annotation {
return []schema.Annotation{
entsql.Annotation{Table: "user_attribute_definitions"},
}
}
func (UserAttributeDefinition) Mixin() []ent.Mixin {
return []ent.Mixin{
mixins.TimeMixin{},
mixins.SoftDeleteMixin{},
}
}
func (UserAttributeDefinition) Fields() []ent.Field {
return []ent.Field{
// key: Unique identifier for the attribute (e.g., "company_name")
// Used for programmatic reference
field.String("key").
MaxLen(100).
NotEmpty(),
// name: Display name shown in forms (e.g., "Company Name")
field.String("name").
MaxLen(255).
NotEmpty(),
// description: Optional description/help text for the attribute
field.String("description").
SchemaType(map[string]string{dialect.Postgres: "text"}).
Default(""),
// type: Attribute type - text, textarea, number, email, url, date, select, multi_select
field.String("type").
MaxLen(20).
NotEmpty(),
// options: Select options for select/multi_select types (stored as JSONB)
// Format: [{"value": "xxx", "label": "XXX"}, ...]
field.JSON("options", []map[string]any{}).
Default([]map[string]any{}).
SchemaType(map[string]string{dialect.Postgres: "jsonb"}),
// required: Whether this attribute is required when editing a user
field.Bool("required").
Default(false),
// validation: Validation rules for the attribute value (stored as JSONB)
// Format: {"min_length": 1, "max_length": 100, "min": 0, "max": 100, "pattern": "^[a-z]+$", "message": "..."}
field.JSON("validation", map[string]any{}).
Default(map[string]any{}).
SchemaType(map[string]string{dialect.Postgres: "jsonb"}),
// placeholder: Placeholder text shown in input fields
field.String("placeholder").
MaxLen(255).
Default(""),
// display_order: Order in which attributes are displayed (lower = first)
field.Int("display_order").
Default(0),
// enabled: Whether this attribute is active and shown in forms
field.Bool("enabled").
Default(true),
}
}
func (UserAttributeDefinition) Edges() []ent.Edge {
return []ent.Edge{
// values: All user values for this attribute definition
edge.To("values", UserAttributeValue.Type),
}
}
func (UserAttributeDefinition) Indexes() []ent.Index {
return []ent.Index{
// Partial unique index on key (WHERE deleted_at IS NULL) via migration
index.Fields("key"),
index.Fields("enabled"),
index.Fields("display_order"),
index.Fields("deleted_at"),
}
}
package schema
import (
"github.com/Wei-Shaw/sub2api/ent/schema/mixins"
"entgo.io/ent"
"entgo.io/ent/dialect/entsql"
"entgo.io/ent/schema"
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
"entgo.io/ent/schema/index"
)
// UserAttributeValue holds a user's value for a specific attribute.
//
// This entity stores the actual values that users have for each attribute definition.
// Values are stored as strings and converted to the appropriate type by the application.
type UserAttributeValue struct {
ent.Schema
}
func (UserAttributeValue) Annotations() []schema.Annotation {
return []schema.Annotation{
entsql.Annotation{Table: "user_attribute_values"},
}
}
func (UserAttributeValue) Mixin() []ent.Mixin {
return []ent.Mixin{
// Only use TimeMixin, no soft delete - values are hard deleted
mixins.TimeMixin{},
}
}
func (UserAttributeValue) Fields() []ent.Field {
return []ent.Field{
// user_id: References the user this value belongs to
field.Int64("user_id"),
// attribute_id: References the attribute definition
field.Int64("attribute_id"),
// value: The actual value stored as a string
// For multi_select, this is a JSON array string
field.Text("value").
Default(""),
}
}
func (UserAttributeValue) Edges() []ent.Edge {
return []ent.Edge{
// user: The user who owns this attribute value
edge.From("user", User.Type).
Ref("attribute_values").
Field("user_id").
Required().
Unique(),
// definition: The attribute definition this value is for
edge.From("definition", UserAttributeDefinition.Type).
Ref("values").
Field("attribute_id").
Required().
Unique(),
}
}
func (UserAttributeValue) Indexes() []ent.Index {
return []ent.Index{
// Unique index on (user_id, attribute_id)
index.Fields("user_id", "attribute_id").Unique(),
index.Fields("attribute_id"),
}
}
...@@ -34,6 +34,10 @@ type Tx struct { ...@@ -34,6 +34,10 @@ type Tx struct {
User *UserClient User *UserClient
// UserAllowedGroup is the client for interacting with the UserAllowedGroup builders. // UserAllowedGroup is the client for interacting with the UserAllowedGroup builders.
UserAllowedGroup *UserAllowedGroupClient UserAllowedGroup *UserAllowedGroupClient
// UserAttributeDefinition is the client for interacting with the UserAttributeDefinition builders.
UserAttributeDefinition *UserAttributeDefinitionClient
// UserAttributeValue is the client for interacting with the UserAttributeValue builders.
UserAttributeValue *UserAttributeValueClient
// UserSubscription is the client for interacting with the UserSubscription builders. // UserSubscription is the client for interacting with the UserSubscription builders.
UserSubscription *UserSubscriptionClient UserSubscription *UserSubscriptionClient
...@@ -177,6 +181,8 @@ func (tx *Tx) init() { ...@@ -177,6 +181,8 @@ func (tx *Tx) init() {
tx.UsageLog = NewUsageLogClient(tx.config) tx.UsageLog = NewUsageLogClient(tx.config)
tx.User = NewUserClient(tx.config) tx.User = NewUserClient(tx.config)
tx.UserAllowedGroup = NewUserAllowedGroupClient(tx.config) tx.UserAllowedGroup = NewUserAllowedGroupClient(tx.config)
tx.UserAttributeDefinition = NewUserAttributeDefinitionClient(tx.config)
tx.UserAttributeValue = NewUserAttributeValueClient(tx.config)
tx.UserSubscription = NewUserSubscriptionClient(tx.config) tx.UserSubscription = NewUserSubscriptionClient(tx.config)
} }
......
// Code generated by ent, DO NOT EDIT.
package ent
import (
"encoding/json"
"fmt"
"strings"
"time"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"github.com/Wei-Shaw/sub2api/ent/userattributedefinition"
)
// UserAttributeDefinition is the model entity for the UserAttributeDefinition schema.
type UserAttributeDefinition struct {
config `json:"-"`
// ID of the ent.
ID int64 `json:"id,omitempty"`
// CreatedAt holds the value of the "created_at" field.
CreatedAt time.Time `json:"created_at,omitempty"`
// UpdatedAt holds the value of the "updated_at" field.
UpdatedAt time.Time `json:"updated_at,omitempty"`
// DeletedAt holds the value of the "deleted_at" field.
DeletedAt *time.Time `json:"deleted_at,omitempty"`
// Key holds the value of the "key" field.
Key string `json:"key,omitempty"`
// Name holds the value of the "name" field.
Name string `json:"name,omitempty"`
// Description holds the value of the "description" field.
Description string `json:"description,omitempty"`
// Type holds the value of the "type" field.
Type string `json:"type,omitempty"`
// Options holds the value of the "options" field.
Options []map[string]interface{} `json:"options,omitempty"`
// Required holds the value of the "required" field.
Required bool `json:"required,omitempty"`
// Validation holds the value of the "validation" field.
Validation map[string]interface{} `json:"validation,omitempty"`
// Placeholder holds the value of the "placeholder" field.
Placeholder string `json:"placeholder,omitempty"`
// DisplayOrder holds the value of the "display_order" field.
DisplayOrder int `json:"display_order,omitempty"`
// Enabled holds the value of the "enabled" field.
Enabled bool `json:"enabled,omitempty"`
// Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the UserAttributeDefinitionQuery when eager-loading is set.
Edges UserAttributeDefinitionEdges `json:"edges"`
selectValues sql.SelectValues
}
// UserAttributeDefinitionEdges holds the relations/edges for other nodes in the graph.
type UserAttributeDefinitionEdges struct {
// Values holds the value of the values edge.
Values []*UserAttributeValue `json:"values,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes [1]bool
}
// ValuesOrErr returns the Values value or an error if the edge
// was not loaded in eager-loading.
func (e UserAttributeDefinitionEdges) ValuesOrErr() ([]*UserAttributeValue, error) {
if e.loadedTypes[0] {
return e.Values, nil
}
return nil, &NotLoadedError{edge: "values"}
}
// scanValues returns the types for scanning values from sql.Rows.
func (*UserAttributeDefinition) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns))
for i := range columns {
switch columns[i] {
case userattributedefinition.FieldOptions, userattributedefinition.FieldValidation:
values[i] = new([]byte)
case userattributedefinition.FieldRequired, userattributedefinition.FieldEnabled:
values[i] = new(sql.NullBool)
case userattributedefinition.FieldID, userattributedefinition.FieldDisplayOrder:
values[i] = new(sql.NullInt64)
case userattributedefinition.FieldKey, userattributedefinition.FieldName, userattributedefinition.FieldDescription, userattributedefinition.FieldType, userattributedefinition.FieldPlaceholder:
values[i] = new(sql.NullString)
case userattributedefinition.FieldCreatedAt, userattributedefinition.FieldUpdatedAt, userattributedefinition.FieldDeletedAt:
values[i] = new(sql.NullTime)
default:
values[i] = new(sql.UnknownType)
}
}
return values, nil
}
// assignValues assigns the values that were returned from sql.Rows (after scanning)
// to the UserAttributeDefinition fields.
func (_m *UserAttributeDefinition) assignValues(columns []string, values []any) error {
if m, n := len(values), len(columns); m < n {
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
}
for i := range columns {
switch columns[i] {
case userattributedefinition.FieldID:
value, ok := values[i].(*sql.NullInt64)
if !ok {
return fmt.Errorf("unexpected type %T for field id", value)
}
_m.ID = int64(value.Int64)
case userattributedefinition.FieldCreatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field created_at", values[i])
} else if value.Valid {
_m.CreatedAt = value.Time
}
case userattributedefinition.FieldUpdatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field updated_at", values[i])
} else if value.Valid {
_m.UpdatedAt = value.Time
}
case userattributedefinition.FieldDeletedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field deleted_at", values[i])
} else if value.Valid {
_m.DeletedAt = new(time.Time)
*_m.DeletedAt = value.Time
}
case userattributedefinition.FieldKey:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field key", values[i])
} else if value.Valid {
_m.Key = value.String
}
case userattributedefinition.FieldName:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field name", values[i])
} else if value.Valid {
_m.Name = value.String
}
case userattributedefinition.FieldDescription:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field description", values[i])
} else if value.Valid {
_m.Description = value.String
}
case userattributedefinition.FieldType:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field type", values[i])
} else if value.Valid {
_m.Type = value.String
}
case userattributedefinition.FieldOptions:
if value, ok := values[i].(*[]byte); !ok {
return fmt.Errorf("unexpected type %T for field options", values[i])
} else if value != nil && len(*value) > 0 {
if err := json.Unmarshal(*value, &_m.Options); err != nil {
return fmt.Errorf("unmarshal field options: %w", err)
}
}
case userattributedefinition.FieldRequired:
if value, ok := values[i].(*sql.NullBool); !ok {
return fmt.Errorf("unexpected type %T for field required", values[i])
} else if value.Valid {
_m.Required = value.Bool
}
case userattributedefinition.FieldValidation:
if value, ok := values[i].(*[]byte); !ok {
return fmt.Errorf("unexpected type %T for field validation", values[i])
} else if value != nil && len(*value) > 0 {
if err := json.Unmarshal(*value, &_m.Validation); err != nil {
return fmt.Errorf("unmarshal field validation: %w", err)
}
}
case userattributedefinition.FieldPlaceholder:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field placeholder", values[i])
} else if value.Valid {
_m.Placeholder = value.String
}
case userattributedefinition.FieldDisplayOrder:
if value, ok := values[i].(*sql.NullInt64); !ok {
return fmt.Errorf("unexpected type %T for field display_order", values[i])
} else if value.Valid {
_m.DisplayOrder = int(value.Int64)
}
case userattributedefinition.FieldEnabled:
if value, ok := values[i].(*sql.NullBool); !ok {
return fmt.Errorf("unexpected type %T for field enabled", values[i])
} else if value.Valid {
_m.Enabled = value.Bool
}
default:
_m.selectValues.Set(columns[i], values[i])
}
}
return nil
}
// Value returns the ent.Value that was dynamically selected and assigned to the UserAttributeDefinition.
// This includes values selected through modifiers, order, etc.
func (_m *UserAttributeDefinition) Value(name string) (ent.Value, error) {
return _m.selectValues.Get(name)
}
// QueryValues queries the "values" edge of the UserAttributeDefinition entity.
func (_m *UserAttributeDefinition) QueryValues() *UserAttributeValueQuery {
return NewUserAttributeDefinitionClient(_m.config).QueryValues(_m)
}
// Update returns a builder for updating this UserAttributeDefinition.
// Note that you need to call UserAttributeDefinition.Unwrap() before calling this method if this UserAttributeDefinition
// was returned from a transaction, and the transaction was committed or rolled back.
func (_m *UserAttributeDefinition) Update() *UserAttributeDefinitionUpdateOne {
return NewUserAttributeDefinitionClient(_m.config).UpdateOne(_m)
}
// Unwrap unwraps the UserAttributeDefinition 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.
func (_m *UserAttributeDefinition) Unwrap() *UserAttributeDefinition {
_tx, ok := _m.config.driver.(*txDriver)
if !ok {
panic("ent: UserAttributeDefinition is not a transactional entity")
}
_m.config.driver = _tx.drv
return _m
}
// String implements the fmt.Stringer.
func (_m *UserAttributeDefinition) String() string {
var builder strings.Builder
builder.WriteString("UserAttributeDefinition(")
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
builder.WriteString("created_at=")
builder.WriteString(_m.CreatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("updated_at=")
builder.WriteString(_m.UpdatedAt.Format(time.ANSIC))
builder.WriteString(", ")
if v := _m.DeletedAt; v != nil {
builder.WriteString("deleted_at=")
builder.WriteString(v.Format(time.ANSIC))
}
builder.WriteString(", ")
builder.WriteString("key=")
builder.WriteString(_m.Key)
builder.WriteString(", ")
builder.WriteString("name=")
builder.WriteString(_m.Name)
builder.WriteString(", ")
builder.WriteString("description=")
builder.WriteString(_m.Description)
builder.WriteString(", ")
builder.WriteString("type=")
builder.WriteString(_m.Type)
builder.WriteString(", ")
builder.WriteString("options=")
builder.WriteString(fmt.Sprintf("%v", _m.Options))
builder.WriteString(", ")
builder.WriteString("required=")
builder.WriteString(fmt.Sprintf("%v", _m.Required))
builder.WriteString(", ")
builder.WriteString("validation=")
builder.WriteString(fmt.Sprintf("%v", _m.Validation))
builder.WriteString(", ")
builder.WriteString("placeholder=")
builder.WriteString(_m.Placeholder)
builder.WriteString(", ")
builder.WriteString("display_order=")
builder.WriteString(fmt.Sprintf("%v", _m.DisplayOrder))
builder.WriteString(", ")
builder.WriteString("enabled=")
builder.WriteString(fmt.Sprintf("%v", _m.Enabled))
builder.WriteByte(')')
return builder.String()
}
// UserAttributeDefinitions is a parsable slice of UserAttributeDefinition.
type UserAttributeDefinitions []*UserAttributeDefinition
// Code generated by ent, DO NOT EDIT.
package userattributedefinition
import (
"time"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
)
const (
// Label holds the string label denoting the userattributedefinition type in the database.
Label = "user_attribute_definition"
// FieldID holds the string denoting the id field in the database.
FieldID = "id"
// FieldCreatedAt holds the string denoting the created_at field in the database.
FieldCreatedAt = "created_at"
// FieldUpdatedAt holds the string denoting the updated_at field in the database.
FieldUpdatedAt = "updated_at"
// FieldDeletedAt holds the string denoting the deleted_at field in the database.
FieldDeletedAt = "deleted_at"
// FieldKey holds the string denoting the key field in the database.
FieldKey = "key"
// FieldName holds the string denoting the name field in the database.
FieldName = "name"
// FieldDescription holds the string denoting the description field in the database.
FieldDescription = "description"
// FieldType holds the string denoting the type field in the database.
FieldType = "type"
// FieldOptions holds the string denoting the options field in the database.
FieldOptions = "options"
// FieldRequired holds the string denoting the required field in the database.
FieldRequired = "required"
// FieldValidation holds the string denoting the validation field in the database.
FieldValidation = "validation"
// FieldPlaceholder holds the string denoting the placeholder field in the database.
FieldPlaceholder = "placeholder"
// FieldDisplayOrder holds the string denoting the display_order field in the database.
FieldDisplayOrder = "display_order"
// FieldEnabled holds the string denoting the enabled field in the database.
FieldEnabled = "enabled"
// EdgeValues holds the string denoting the values edge name in mutations.
EdgeValues = "values"
// Table holds the table name of the userattributedefinition in the database.
Table = "user_attribute_definitions"
// ValuesTable is the table that holds the values relation/edge.
ValuesTable = "user_attribute_values"
// ValuesInverseTable is the table name for the UserAttributeValue entity.
// It exists in this package in order to avoid circular dependency with the "userattributevalue" package.
ValuesInverseTable = "user_attribute_values"
// ValuesColumn is the table column denoting the values relation/edge.
ValuesColumn = "attribute_id"
)
// Columns holds all SQL columns for userattributedefinition fields.
var Columns = []string{
FieldID,
FieldCreatedAt,
FieldUpdatedAt,
FieldDeletedAt,
FieldKey,
FieldName,
FieldDescription,
FieldType,
FieldOptions,
FieldRequired,
FieldValidation,
FieldPlaceholder,
FieldDisplayOrder,
FieldEnabled,
}
// ValidColumn reports if the column name is valid (part of the table columns).
func ValidColumn(column string) bool {
for i := range Columns {
if column == Columns[i] {
return true
}
}
return false
}
// Note that the variables below are initialized by the runtime
// package on the initialization of the application. Therefore,
// it should be imported in the main as follows:
//
// import _ "github.com/Wei-Shaw/sub2api/ent/runtime"
var (
Hooks [1]ent.Hook
Interceptors [1]ent.Interceptor
// DefaultCreatedAt holds the default value on creation for the "created_at" field.
DefaultCreatedAt func() time.Time
// DefaultUpdatedAt holds the default value on creation for the "updated_at" field.
DefaultUpdatedAt func() time.Time
// UpdateDefaultUpdatedAt holds the default value on update for the "updated_at" field.
UpdateDefaultUpdatedAt func() time.Time
// KeyValidator is a validator for the "key" field. It is called by the builders before save.
KeyValidator func(string) error
// NameValidator is a validator for the "name" field. It is called by the builders before save.
NameValidator func(string) error
// DefaultDescription holds the default value on creation for the "description" field.
DefaultDescription string
// TypeValidator is a validator for the "type" field. It is called by the builders before save.
TypeValidator func(string) error
// DefaultOptions holds the default value on creation for the "options" field.
DefaultOptions []map[string]interface{}
// DefaultRequired holds the default value on creation for the "required" field.
DefaultRequired bool
// DefaultValidation holds the default value on creation for the "validation" field.
DefaultValidation map[string]interface{}
// DefaultPlaceholder holds the default value on creation for the "placeholder" field.
DefaultPlaceholder string
// PlaceholderValidator is a validator for the "placeholder" field. It is called by the builders before save.
PlaceholderValidator func(string) error
// DefaultDisplayOrder holds the default value on creation for the "display_order" field.
DefaultDisplayOrder int
// DefaultEnabled holds the default value on creation for the "enabled" field.
DefaultEnabled bool
)
// OrderOption defines the ordering options for the UserAttributeDefinition queries.
type OrderOption func(*sql.Selector)
// ByID orders the results by the id field.
func ByID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldID, opts...).ToFunc()
}
// ByCreatedAt orders the results by the created_at field.
func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldCreatedAt, opts...).ToFunc()
}
// ByUpdatedAt orders the results by the updated_at field.
func ByUpdatedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldUpdatedAt, opts...).ToFunc()
}
// ByDeletedAt orders the results by the deleted_at field.
func ByDeletedAt(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDeletedAt, opts...).ToFunc()
}
// ByKey orders the results by the key field.
func ByKey(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldKey, opts...).ToFunc()
}
// ByName orders the results by the name field.
func ByName(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldName, opts...).ToFunc()
}
// ByDescription orders the results by the description field.
func ByDescription(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDescription, opts...).ToFunc()
}
// ByType orders the results by the type field.
func ByType(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldType, opts...).ToFunc()
}
// ByRequired orders the results by the required field.
func ByRequired(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldRequired, opts...).ToFunc()
}
// ByPlaceholder orders the results by the placeholder field.
func ByPlaceholder(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldPlaceholder, opts...).ToFunc()
}
// ByDisplayOrder orders the results by the display_order field.
func ByDisplayOrder(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldDisplayOrder, opts...).ToFunc()
}
// ByEnabled orders the results by the enabled field.
func ByEnabled(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldEnabled, opts...).ToFunc()
}
// ByValuesCount orders the results by values count.
func ByValuesCount(opts ...sql.OrderTermOption) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborsCount(s, newValuesStep(), opts...)
}
}
// ByValues orders the results by values terms.
func ByValues(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption {
return func(s *sql.Selector) {
sqlgraph.OrderByNeighborTerms(s, newValuesStep(), append([]sql.OrderTerm{term}, terms...)...)
}
}
func newValuesStep() *sqlgraph.Step {
return sqlgraph.NewStep(
sqlgraph.From(Table, FieldID),
sqlgraph.To(ValuesInverseTable, FieldID),
sqlgraph.Edge(sqlgraph.O2M, false, ValuesTable, ValuesColumn),
)
}
This diff is collapsed.
This diff is collapsed.
// Code generated by ent, DO NOT EDIT.
package ent
import (
"context"
"entgo.io/ent/dialect/sql"
"entgo.io/ent/dialect/sql/sqlgraph"
"entgo.io/ent/schema/field"
"github.com/Wei-Shaw/sub2api/ent/predicate"
"github.com/Wei-Shaw/sub2api/ent/userattributedefinition"
)
// UserAttributeDefinitionDelete is the builder for deleting a UserAttributeDefinition entity.
type UserAttributeDefinitionDelete struct {
config
hooks []Hook
mutation *UserAttributeDefinitionMutation
}
// Where appends a list predicates to the UserAttributeDefinitionDelete builder.
func (_d *UserAttributeDefinitionDelete) Where(ps ...predicate.UserAttributeDefinition) *UserAttributeDefinitionDelete {
_d.mutation.Where(ps...)
return _d
}
// Exec executes the deletion query and returns how many vertices were deleted.
func (_d *UserAttributeDefinitionDelete) Exec(ctx context.Context) (int, error) {
return withHooks(ctx, _d.sqlExec, _d.mutation, _d.hooks)
}
// ExecX is like Exec, but panics if an error occurs.
func (_d *UserAttributeDefinitionDelete) ExecX(ctx context.Context) int {
n, err := _d.Exec(ctx)
if err != nil {
panic(err)
}
return n
}
func (_d *UserAttributeDefinitionDelete) sqlExec(ctx context.Context) (int, error) {
_spec := sqlgraph.NewDeleteSpec(userattributedefinition.Table, sqlgraph.NewFieldSpec(userattributedefinition.FieldID, field.TypeInt64))
if ps := _d.mutation.predicates; len(ps) > 0 {
_spec.Predicate = func(selector *sql.Selector) {
for i := range ps {
ps[i](selector)
}
}
}
affected, err := sqlgraph.DeleteNodes(ctx, _d.driver, _spec)
if err != nil && sqlgraph.IsConstraintError(err) {
err = &ConstraintError{msg: err.Error(), wrap: err}
}
_d.mutation.done = true
return affected, err
}
// UserAttributeDefinitionDeleteOne is the builder for deleting a single UserAttributeDefinition entity.
type UserAttributeDefinitionDeleteOne struct {
_d *UserAttributeDefinitionDelete
}
// Where appends a list predicates to the UserAttributeDefinitionDelete builder.
func (_d *UserAttributeDefinitionDeleteOne) Where(ps ...predicate.UserAttributeDefinition) *UserAttributeDefinitionDeleteOne {
_d._d.mutation.Where(ps...)
return _d
}
// Exec executes the deletion query.
func (_d *UserAttributeDefinitionDeleteOne) Exec(ctx context.Context) error {
n, err := _d._d.Exec(ctx)
switch {
case err != nil:
return err
case n == 0:
return &NotFoundError{userattributedefinition.Label}
default:
return nil
}
}
// ExecX is like Exec, but panics if an error occurs.
func (_d *UserAttributeDefinitionDeleteOne) ExecX(ctx context.Context) {
if err := _d.Exec(ctx); err != nil {
panic(err)
}
}
This diff is collapsed.
This diff is collapsed.
// Code generated by ent, DO NOT EDIT.
package ent
import (
"fmt"
"strings"
"time"
"entgo.io/ent"
"entgo.io/ent/dialect/sql"
"github.com/Wei-Shaw/sub2api/ent/user"
"github.com/Wei-Shaw/sub2api/ent/userattributedefinition"
"github.com/Wei-Shaw/sub2api/ent/userattributevalue"
)
// UserAttributeValue is the model entity for the UserAttributeValue schema.
type UserAttributeValue struct {
config `json:"-"`
// ID of the ent.
ID int64 `json:"id,omitempty"`
// CreatedAt holds the value of the "created_at" field.
CreatedAt time.Time `json:"created_at,omitempty"`
// UpdatedAt holds the value of the "updated_at" field.
UpdatedAt time.Time `json:"updated_at,omitempty"`
// UserID holds the value of the "user_id" field.
UserID int64 `json:"user_id,omitempty"`
// AttributeID holds the value of the "attribute_id" field.
AttributeID int64 `json:"attribute_id,omitempty"`
// Value holds the value of the "value" field.
Value string `json:"value,omitempty"`
// Edges holds the relations/edges for other nodes in the graph.
// The values are being populated by the UserAttributeValueQuery when eager-loading is set.
Edges UserAttributeValueEdges `json:"edges"`
selectValues sql.SelectValues
}
// UserAttributeValueEdges holds the relations/edges for other nodes in the graph.
type UserAttributeValueEdges struct {
// User holds the value of the user edge.
User *User `json:"user,omitempty"`
// Definition holds the value of the definition edge.
Definition *UserAttributeDefinition `json:"definition,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes [2]bool
}
// UserOrErr returns the User value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e UserAttributeValueEdges) UserOrErr() (*User, error) {
if e.User != nil {
return e.User, nil
} else if e.loadedTypes[0] {
return nil, &NotFoundError{label: user.Label}
}
return nil, &NotLoadedError{edge: "user"}
}
// DefinitionOrErr returns the Definition value or an error if the edge
// was not loaded in eager-loading, or loaded but was not found.
func (e UserAttributeValueEdges) DefinitionOrErr() (*UserAttributeDefinition, error) {
if e.Definition != nil {
return e.Definition, nil
} else if e.loadedTypes[1] {
return nil, &NotFoundError{label: userattributedefinition.Label}
}
return nil, &NotLoadedError{edge: "definition"}
}
// scanValues returns the types for scanning values from sql.Rows.
func (*UserAttributeValue) scanValues(columns []string) ([]any, error) {
values := make([]any, len(columns))
for i := range columns {
switch columns[i] {
case userattributevalue.FieldID, userattributevalue.FieldUserID, userattributevalue.FieldAttributeID:
values[i] = new(sql.NullInt64)
case userattributevalue.FieldValue:
values[i] = new(sql.NullString)
case userattributevalue.FieldCreatedAt, userattributevalue.FieldUpdatedAt:
values[i] = new(sql.NullTime)
default:
values[i] = new(sql.UnknownType)
}
}
return values, nil
}
// assignValues assigns the values that were returned from sql.Rows (after scanning)
// to the UserAttributeValue fields.
func (_m *UserAttributeValue) assignValues(columns []string, values []any) error {
if m, n := len(values), len(columns); m < n {
return fmt.Errorf("mismatch number of scan values: %d != %d", m, n)
}
for i := range columns {
switch columns[i] {
case userattributevalue.FieldID:
value, ok := values[i].(*sql.NullInt64)
if !ok {
return fmt.Errorf("unexpected type %T for field id", value)
}
_m.ID = int64(value.Int64)
case userattributevalue.FieldCreatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field created_at", values[i])
} else if value.Valid {
_m.CreatedAt = value.Time
}
case userattributevalue.FieldUpdatedAt:
if value, ok := values[i].(*sql.NullTime); !ok {
return fmt.Errorf("unexpected type %T for field updated_at", values[i])
} else if value.Valid {
_m.UpdatedAt = value.Time
}
case userattributevalue.FieldUserID:
if value, ok := values[i].(*sql.NullInt64); !ok {
return fmt.Errorf("unexpected type %T for field user_id", values[i])
} else if value.Valid {
_m.UserID = value.Int64
}
case userattributevalue.FieldAttributeID:
if value, ok := values[i].(*sql.NullInt64); !ok {
return fmt.Errorf("unexpected type %T for field attribute_id", values[i])
} else if value.Valid {
_m.AttributeID = value.Int64
}
case userattributevalue.FieldValue:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field value", values[i])
} else if value.Valid {
_m.Value = value.String
}
default:
_m.selectValues.Set(columns[i], values[i])
}
}
return nil
}
// GetValue returns the ent.Value that was dynamically selected and assigned to the UserAttributeValue.
// This includes values selected through modifiers, order, etc.
func (_m *UserAttributeValue) GetValue(name string) (ent.Value, error) {
return _m.selectValues.Get(name)
}
// QueryUser queries the "user" edge of the UserAttributeValue entity.
func (_m *UserAttributeValue) QueryUser() *UserQuery {
return NewUserAttributeValueClient(_m.config).QueryUser(_m)
}
// QueryDefinition queries the "definition" edge of the UserAttributeValue entity.
func (_m *UserAttributeValue) QueryDefinition() *UserAttributeDefinitionQuery {
return NewUserAttributeValueClient(_m.config).QueryDefinition(_m)
}
// Update returns a builder for updating this UserAttributeValue.
// Note that you need to call UserAttributeValue.Unwrap() before calling this method if this UserAttributeValue
// was returned from a transaction, and the transaction was committed or rolled back.
func (_m *UserAttributeValue) Update() *UserAttributeValueUpdateOne {
return NewUserAttributeValueClient(_m.config).UpdateOne(_m)
}
// Unwrap unwraps the UserAttributeValue 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.
func (_m *UserAttributeValue) Unwrap() *UserAttributeValue {
_tx, ok := _m.config.driver.(*txDriver)
if !ok {
panic("ent: UserAttributeValue is not a transactional entity")
}
_m.config.driver = _tx.drv
return _m
}
// String implements the fmt.Stringer.
func (_m *UserAttributeValue) String() string {
var builder strings.Builder
builder.WriteString("UserAttributeValue(")
builder.WriteString(fmt.Sprintf("id=%v, ", _m.ID))
builder.WriteString("created_at=")
builder.WriteString(_m.CreatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("updated_at=")
builder.WriteString(_m.UpdatedAt.Format(time.ANSIC))
builder.WriteString(", ")
builder.WriteString("user_id=")
builder.WriteString(fmt.Sprintf("%v", _m.UserID))
builder.WriteString(", ")
builder.WriteString("attribute_id=")
builder.WriteString(fmt.Sprintf("%v", _m.AttributeID))
builder.WriteString(", ")
builder.WriteString("value=")
builder.WriteString(_m.Value)
builder.WriteByte(')')
return builder.String()
}
// UserAttributeValues is a parsable slice of UserAttributeValue.
type UserAttributeValues []*UserAttributeValue
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment