diff --git a/ent/client.go b/ent/client.go index 06129e13..fb304afb 100644 --- a/ent/client.go +++ b/ent/client.go @@ -20,6 +20,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/file" "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/membership" "github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/passkey" @@ -47,6 +48,8 @@ type Client struct { File *FileClient // Group is the client for interacting with the Group builders. Group *GroupClient + // Membership is the client for interacting with the Membership builders. + Membership *MembershipClient // Metadata is the client for interacting with the Metadata builders. Metadata *MetadataClient // Node is the client for interacting with the Node builders. @@ -79,6 +82,7 @@ func (c *Client) init() { c.Entity = NewEntityClient(c.config) c.File = NewFileClient(c.config) c.Group = NewGroupClient(c.config) + c.Membership = NewMembershipClient(c.config) c.Metadata = NewMetadataClient(c.config) c.Node = NewNodeClient(c.config) c.Passkey = NewPasskeyClient(c.config) @@ -184,6 +188,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) { Entity: NewEntityClient(cfg), File: NewFileClient(cfg), Group: NewGroupClient(cfg), + Membership: NewMembershipClient(cfg), Metadata: NewMetadataClient(cfg), Node: NewNodeClient(cfg), Passkey: NewPasskeyClient(cfg), @@ -216,6 +221,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) Entity: NewEntityClient(cfg), File: NewFileClient(cfg), Group: NewGroupClient(cfg), + Membership: NewMembershipClient(cfg), Metadata: NewMetadataClient(cfg), Node: NewNodeClient(cfg), Passkey: NewPasskeyClient(cfg), @@ -253,8 +259,8 @@ func (c *Client) Close() error { // In order to add hooks to a specific client, call: `client.Node.Use(...)`. func (c *Client) Use(hooks ...Hook) { for _, n := range []interface{ Use(...Hook) }{ - c.DavAccount, c.DirectLink, c.Entity, c.File, c.Group, c.Metadata, c.Node, - c.Passkey, c.Setting, c.Share, c.StoragePolicy, c.Task, c.User, + c.DavAccount, c.DirectLink, c.Entity, c.File, c.Group, c.Membership, c.Metadata, + c.Node, c.Passkey, c.Setting, c.Share, c.StoragePolicy, c.Task, c.User, } { n.Use(hooks...) } @@ -264,8 +270,8 @@ func (c *Client) Use(hooks ...Hook) { // In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`. func (c *Client) Intercept(interceptors ...Interceptor) { for _, n := range []interface{ Intercept(...Interceptor) }{ - c.DavAccount, c.DirectLink, c.Entity, c.File, c.Group, c.Metadata, c.Node, - c.Passkey, c.Setting, c.Share, c.StoragePolicy, c.Task, c.User, + c.DavAccount, c.DirectLink, c.Entity, c.File, c.Group, c.Membership, c.Metadata, + c.Node, c.Passkey, c.Setting, c.Share, c.StoragePolicy, c.Task, c.User, } { n.Intercept(interceptors...) } @@ -284,6 +290,8 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { return c.File.mutate(ctx, m) case *GroupMutation: return c.Group.mutate(ctx, m) + case *MembershipMutation: + return c.Membership.mutate(ctx, m) case *MetadataMutation: return c.Metadata.mutate(ctx, m) case *NodeMutation: @@ -1168,7 +1176,7 @@ func (c *GroupClient) QueryUsers(gr *Group) *UserQuery { step := sqlgraph.NewStep( sqlgraph.From(group.Table, group.FieldID, id), sqlgraph.To(user.Table, user.FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, group.UsersTable, group.UsersColumn), + sqlgraph.Edge(sqlgraph.M2M, false, group.UsersTable, group.UsersPrimaryKey...), ) fromV = sqlgraph.Neighbors(gr.driver.Dialect(), step) return fromV, nil @@ -1192,6 +1200,22 @@ func (c *GroupClient) QueryStoragePolicies(gr *Group) *StoragePolicyQuery { return query } +// QueryMembership queries the membership edge of a Group. +func (c *GroupClient) QueryMembership(gr *Group) *MembershipQuery { + query := (&MembershipClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := gr.ID + step := sqlgraph.NewStep( + sqlgraph.From(group.Table, group.FieldID, id), + sqlgraph.To(membership.Table, membership.GroupColumn), + sqlgraph.Edge(sqlgraph.O2M, true, group.MembershipTable, group.MembershipColumn), + ) + fromV = sqlgraph.Neighbors(gr.driver.Dialect(), step) + return fromV, nil + } + return query +} + // Hooks returns the client hooks. func (c *GroupClient) Hooks() []Hook { hooks := c.hooks.Group @@ -1219,6 +1243,122 @@ func (c *GroupClient) mutate(ctx context.Context, m *GroupMutation) (Value, erro } } +// MembershipClient is a client for the Membership schema. +type MembershipClient struct { + config +} + +// NewMembershipClient returns a client for the Membership from the given config. +func NewMembershipClient(c config) *MembershipClient { + return &MembershipClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `membership.Hooks(f(g(h())))`. +func (c *MembershipClient) Use(hooks ...Hook) { + c.hooks.Membership = append(c.hooks.Membership, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `membership.Intercept(f(g(h())))`. +func (c *MembershipClient) Intercept(interceptors ...Interceptor) { + c.inters.Membership = append(c.inters.Membership, interceptors...) +} + +// Create returns a builder for creating a Membership entity. +func (c *MembershipClient) Create() *MembershipCreate { + mutation := newMembershipMutation(c.config, OpCreate) + return &MembershipCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of Membership entities. +func (c *MembershipClient) CreateBulk(builders ...*MembershipCreate) *MembershipCreateBulk { + return &MembershipCreateBulk{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 *MembershipClient) MapCreateBulk(slice any, setFunc func(*MembershipCreate, int)) *MembershipCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &MembershipCreateBulk{err: fmt.Errorf("calling to MembershipClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*MembershipCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &MembershipCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for Membership. +func (c *MembershipClient) Update() *MembershipUpdate { + mutation := newMembershipMutation(c.config, OpUpdate) + return &MembershipUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *MembershipClient) UpdateOne(m *Membership) *MembershipUpdateOne { + mutation := newMembershipMutation(c.config, OpUpdateOne) + mutation.group = &m.GroupID + mutation.user = &m.UserID + return &MembershipUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for Membership. +func (c *MembershipClient) Delete() *MembershipDelete { + mutation := newMembershipMutation(c.config, OpDelete) + return &MembershipDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Query returns a query builder for Membership. +func (c *MembershipClient) Query() *MembershipQuery { + return &MembershipQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeMembership}, + inters: c.Interceptors(), + } +} + +// QueryUser queries the user edge of a Membership. +func (c *MembershipClient) QueryUser(m *Membership) *UserQuery { + return c.Query(). + Where(membership.GroupID(m.GroupID), membership.UserID(m.UserID)). + QueryUser() +} + +// QueryGroup queries the group edge of a Membership. +func (c *MembershipClient) QueryGroup(m *Membership) *GroupQuery { + return c.Query(). + Where(membership.GroupID(m.GroupID), membership.UserID(m.UserID)). + QueryGroup() +} + +// Hooks returns the client hooks. +func (c *MembershipClient) Hooks() []Hook { + return c.hooks.Membership +} + +// Interceptors returns the client interceptors. +func (c *MembershipClient) Interceptors() []Interceptor { + return c.inters.Membership +} + +func (c *MembershipClient) mutate(ctx context.Context, m *MembershipMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&MembershipCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&MembershipUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&MembershipUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&MembershipDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown Membership mutation op: %q", m.Op()) + } +} + // MetadataClient is a client for the Metadata schema. type MetadataClient struct { config @@ -2440,7 +2580,7 @@ func (c *UserClient) QueryGroup(u *User) *GroupQuery { step := sqlgraph.NewStep( sqlgraph.From(user.Table, user.FieldID, id), sqlgraph.To(group.Table, group.FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, user.GroupTable, user.GroupColumn), + sqlgraph.Edge(sqlgraph.M2M, true, user.GroupTable, user.GroupPrimaryKey...), ) fromV = sqlgraph.Neighbors(u.driver.Dialect(), step) return fromV, nil @@ -2544,6 +2684,22 @@ func (c *UserClient) QueryEntities(u *User) *EntityQuery { return query } +// QueryMembership queries the membership edge of a User. +func (c *UserClient) QueryMembership(u *User) *MembershipQuery { + query := (&MembershipClient{config: c.config}).Query() + query.path = func(context.Context) (fromV *sql.Selector, _ error) { + id := u.ID + step := sqlgraph.NewStep( + sqlgraph.From(user.Table, user.FieldID, id), + sqlgraph.To(membership.Table, membership.UserColumn), + sqlgraph.Edge(sqlgraph.O2M, true, user.MembershipTable, user.MembershipColumn), + ) + fromV = sqlgraph.Neighbors(u.driver.Dialect(), step) + return fromV, nil + } + return query +} + // Hooks returns the client hooks. func (c *UserClient) Hooks() []Hook { hooks := c.hooks.User @@ -2574,12 +2730,12 @@ func (c *UserClient) mutate(ctx context.Context, m *UserMutation) (Value, error) // hooks and interceptors per client, for fast access. type ( hooks struct { - DavAccount, DirectLink, Entity, File, Group, Metadata, Node, Passkey, Setting, - Share, StoragePolicy, Task, User []ent.Hook + DavAccount, DirectLink, Entity, File, Group, Membership, Metadata, Node, + Passkey, Setting, Share, StoragePolicy, Task, User []ent.Hook } inters struct { - DavAccount, DirectLink, Entity, File, Group, Metadata, Node, Passkey, Setting, - Share, StoragePolicy, Task, User []ent.Interceptor + DavAccount, DirectLink, Entity, File, Group, Membership, Metadata, Node, + Passkey, Setting, Share, StoragePolicy, Task, User []ent.Interceptor } ) diff --git a/ent/ent.go b/ent/ent.go index 4026fe67..9bed72ff 100644 --- a/ent/ent.go +++ b/ent/ent.go @@ -17,6 +17,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/file" "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/membership" "github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/passkey" @@ -90,6 +91,7 @@ func checkColumn(table, column string) error { entity.Table: entity.ValidColumn, file.Table: file.ValidColumn, group.Table: group.ValidColumn, + membership.Table: membership.ValidColumn, metadata.Table: metadata.ValidColumn, node.Table: node.ValidColumn, passkey.Table: passkey.ValidColumn, diff --git a/ent/group.go b/ent/group.go index 80882cb5..6872d708 100644 --- a/ent/group.go +++ b/ent/group.go @@ -51,9 +51,11 @@ type GroupEdges struct { Users []*User `json:"users,omitempty"` // StoragePolicies holds the value of the storage_policies edge. StoragePolicies *StoragePolicy `json:"storage_policies,omitempty"` + // Membership holds the value of the membership edge. + Membership []*Membership `json:"membership,omitempty"` // loadedTypes holds the information for reporting if a // type was loaded (or requested) in eager-loading or not. - loadedTypes [2]bool + loadedTypes [3]bool } // UsersOrErr returns the Users value or an error if the edge @@ -78,6 +80,15 @@ func (e GroupEdges) StoragePoliciesOrErr() (*StoragePolicy, error) { return nil, &NotLoadedError{edge: "storage_policies"} } +// MembershipOrErr returns the Membership value or an error if the edge +// was not loaded in eager-loading. +func (e GroupEdges) MembershipOrErr() ([]*Membership, error) { + if e.loadedTypes[2] { + return e.Membership, nil + } + return nil, &NotLoadedError{edge: "membership"} +} + // scanValues returns the types for scanning values from sql.Rows. func (*Group) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) @@ -194,6 +205,11 @@ func (gr *Group) QueryStoragePolicies() *StoragePolicyQuery { return NewGroupClient(gr.config).QueryStoragePolicies(gr) } +// QueryMembership queries the "membership" edge of the Group entity. +func (gr *Group) QueryMembership() *MembershipQuery { + return NewGroupClient(gr.config).QueryMembership(gr) +} + // Update returns a builder for updating this Group. // Note that you need to call Group.Unwrap() before calling this method if this Group // was returned from a transaction, and the transaction was committed or rolled back. @@ -261,5 +277,11 @@ func (e *Group) SetStoragePolicies(v *StoragePolicy) { e.Edges.loadedTypes[1] = true } +// SetMembership manually set the edge as loaded state. +func (e *Group) SetMembership(v []*Membership) { + e.Edges.Membership = v + e.Edges.loadedTypes[2] = true +} + // Groups is a parsable slice of Group. type Groups []*Group diff --git a/ent/group/group.go b/ent/group/group.go index 7ceee545..7f85fb95 100644 --- a/ent/group/group.go +++ b/ent/group/group.go @@ -38,15 +38,15 @@ const ( EdgeUsers = "users" // EdgeStoragePolicies holds the string denoting the storage_policies edge name in mutations. EdgeStoragePolicies = "storage_policies" + // EdgeMembership holds the string denoting the membership edge name in mutations. + EdgeMembership = "membership" // Table holds the table name of the group in the database. Table = "groups" - // UsersTable is the table that holds the users relation/edge. - UsersTable = "users" + // UsersTable is the table that holds the users relation/edge. The primary key declared below. + UsersTable = "memberships" // UsersInverseTable is the table name for the User entity. // It exists in this package in order to avoid circular dependency with the "user" package. UsersInverseTable = "users" - // UsersColumn is the table column denoting the users relation/edge. - UsersColumn = "group_users" // StoragePoliciesTable is the table that holds the storage_policies relation/edge. StoragePoliciesTable = "groups" // StoragePoliciesInverseTable is the table name for the StoragePolicy entity. @@ -54,6 +54,13 @@ const ( StoragePoliciesInverseTable = "storage_policies" // StoragePoliciesColumn is the table column denoting the storage_policies relation/edge. StoragePoliciesColumn = "storage_policy_id" + // MembershipTable is the table that holds the membership relation/edge. + MembershipTable = "memberships" + // MembershipInverseTable is the table name for the Membership entity. + // It exists in this package in order to avoid circular dependency with the "membership" package. + MembershipInverseTable = "memberships" + // MembershipColumn is the table column denoting the membership relation/edge. + MembershipColumn = "group_id" ) // Columns holds all SQL columns for group fields. @@ -70,6 +77,12 @@ var Columns = []string{ FieldStoragePolicyID, } +var ( + // UsersPrimaryKey and UsersColumn2 are the table columns denoting the + // primary key for the users relation (M2M). + UsersPrimaryKey = []string{"group_id", "user_id"} +) + // ValidColumn reports if the column name is valid (part of the table columns). func ValidColumn(column string) bool { for i := range Columns { @@ -161,11 +174,25 @@ func ByStoragePoliciesField(field string, opts ...sql.OrderTermOption) OrderOpti sqlgraph.OrderByNeighborTerms(s, newStoragePoliciesStep(), sql.OrderByField(field, opts...)) } } + +// ByMembershipCount orders the results by membership count. +func ByMembershipCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newMembershipStep(), opts...) + } +} + +// ByMembership orders the results by membership terms. +func ByMembership(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newMembershipStep(), append([]sql.OrderTerm{term}, terms...)...) + } +} func newUsersStep() *sqlgraph.Step { return sqlgraph.NewStep( sqlgraph.From(Table, FieldID), sqlgraph.To(UsersInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, UsersTable, UsersColumn), + sqlgraph.Edge(sqlgraph.M2M, false, UsersTable, UsersPrimaryKey...), ) } func newStoragePoliciesStep() *sqlgraph.Step { @@ -175,3 +202,10 @@ func newStoragePoliciesStep() *sqlgraph.Step { sqlgraph.Edge(sqlgraph.M2O, true, StoragePoliciesTable, StoragePoliciesColumn), ) } +func newMembershipStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(MembershipInverseTable, MembershipColumn), + sqlgraph.Edge(sqlgraph.O2M, true, MembershipTable, MembershipColumn), + ) +} diff --git a/ent/group/where.go b/ent/group/where.go index 4c414ff5..91e41dd1 100644 --- a/ent/group/where.go +++ b/ent/group/where.go @@ -476,7 +476,7 @@ func HasUsers() predicate.Group { return predicate.Group(func(s *sql.Selector) { step := sqlgraph.NewStep( sqlgraph.From(Table, FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, UsersTable, UsersColumn), + sqlgraph.Edge(sqlgraph.M2M, false, UsersTable, UsersPrimaryKey...), ) sqlgraph.HasNeighbors(s, step) }) @@ -517,6 +517,29 @@ func HasStoragePoliciesWith(preds ...predicate.StoragePolicy) predicate.Group { }) } +// HasMembership applies the HasEdge predicate on the "membership" edge. +func HasMembership() predicate.Group { + return predicate.Group(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, MembershipTable, MembershipColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasMembershipWith applies the HasEdge predicate on the "membership" edge with a given conditions (other predicates). +func HasMembershipWith(preds ...predicate.Membership) predicate.Group { + return predicate.Group(func(s *sql.Selector) { + step := newMembershipStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + // And groups predicates with the AND operator between them. func And(predicates ...predicate.Group) predicate.Group { return predicate.Group(sql.AndPredicates(predicates...)) diff --git a/ent/group_create.go b/ent/group_create.go index e11afdd6..e9b4be94 100644 --- a/ent/group_create.go +++ b/ent/group_create.go @@ -302,10 +302,10 @@ func (gc *GroupCreate) createSpec() (*Group, *sqlgraph.CreateSpec) { } if nodes := gc.mutation.UsersIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.O2M, + Rel: sqlgraph.M2M, Inverse: false, Table: group.UsersTable, - Columns: []string{group.UsersColumn}, + Columns: group.UsersPrimaryKey, Bidi: false, Target: &sqlgraph.EdgeTarget{ IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt), @@ -314,6 +314,10 @@ func (gc *GroupCreate) createSpec() (*Group, *sqlgraph.CreateSpec) { for _, k := range nodes { edge.Target.Nodes = append(edge.Target.Nodes, k) } + createE := &MembershipCreate{config: gc.config, mutation: newMembershipMutation(gc.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields _spec.Edges = append(_spec.Edges, edge) } if nodes := gc.mutation.StoragePoliciesIDs(); len(nodes) > 0 { diff --git a/ent/group_query.go b/ent/group_query.go index 27d4ac91..7ae55ad0 100644 --- a/ent/group_query.go +++ b/ent/group_query.go @@ -12,6 +12,7 @@ import ( "entgo.io/ent/dialect/sql/sqlgraph" "entgo.io/ent/schema/field" "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/membership" "github.com/cloudreve/Cloudreve/v4/ent/predicate" "github.com/cloudreve/Cloudreve/v4/ent/storagepolicy" "github.com/cloudreve/Cloudreve/v4/ent/user" @@ -26,6 +27,7 @@ type GroupQuery struct { predicates []predicate.Group withUsers *UserQuery withStoragePolicies *StoragePolicyQuery + withMembership *MembershipQuery // intermediate query (i.e. traversal path). sql *sql.Selector path func(context.Context) (*sql.Selector, error) @@ -76,7 +78,7 @@ func (gq *GroupQuery) QueryUsers() *UserQuery { step := sqlgraph.NewStep( sqlgraph.From(group.Table, group.FieldID, selector), sqlgraph.To(user.Table, user.FieldID), - sqlgraph.Edge(sqlgraph.O2M, false, group.UsersTable, group.UsersColumn), + sqlgraph.Edge(sqlgraph.M2M, false, group.UsersTable, group.UsersPrimaryKey...), ) fromU = sqlgraph.SetNeighbors(gq.driver.Dialect(), step) return fromU, nil @@ -106,6 +108,28 @@ func (gq *GroupQuery) QueryStoragePolicies() *StoragePolicyQuery { return query } +// QueryMembership chains the current query on the "membership" edge. +func (gq *GroupQuery) QueryMembership() *MembershipQuery { + query := (&MembershipClient{config: gq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := gq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := gq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(group.Table, group.FieldID, selector), + sqlgraph.To(membership.Table, membership.GroupColumn), + sqlgraph.Edge(sqlgraph.O2M, true, group.MembershipTable, group.MembershipColumn), + ) + fromU = sqlgraph.SetNeighbors(gq.driver.Dialect(), step) + return fromU, nil + } + return query +} + // First returns the first Group entity from the query. // Returns a *NotFoundError when no Group was found. func (gq *GroupQuery) First(ctx context.Context) (*Group, error) { @@ -300,6 +324,7 @@ func (gq *GroupQuery) Clone() *GroupQuery { predicates: append([]predicate.Group{}, gq.predicates...), withUsers: gq.withUsers.Clone(), withStoragePolicies: gq.withStoragePolicies.Clone(), + withMembership: gq.withMembership.Clone(), // clone intermediate query. sql: gq.sql.Clone(), path: gq.path, @@ -328,6 +353,17 @@ func (gq *GroupQuery) WithStoragePolicies(opts ...func(*StoragePolicyQuery)) *Gr return gq } +// WithMembership tells the query-builder to eager-load the nodes that are connected to +// the "membership" edge. The optional arguments are used to configure the query builder of the edge. +func (gq *GroupQuery) WithMembership(opts ...func(*MembershipQuery)) *GroupQuery { + query := (&MembershipClient{config: gq.config}).Query() + for _, opt := range opts { + opt(query) + } + gq.withMembership = query + return gq +} + // GroupBy is used to group vertices by one or more fields/columns. // It is often used with aggregate functions, like: count, max, mean, min, sum. // @@ -406,9 +442,10 @@ func (gq *GroupQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Group, var ( nodes = []*Group{} _spec = gq.querySpec() - loadedTypes = [2]bool{ + loadedTypes = [3]bool{ gq.withUsers != nil, gq.withStoragePolicies != nil, + gq.withMembership != nil, } ) _spec.ScanValues = func(columns []string) ([]any, error) { @@ -442,36 +479,74 @@ func (gq *GroupQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Group, return nil, err } } + if query := gq.withMembership; query != nil { + if err := gq.loadMembership(ctx, query, nodes, + func(n *Group) { n.Edges.Membership = []*Membership{} }, + func(n *Group, e *Membership) { n.Edges.Membership = append(n.Edges.Membership, e) }); err != nil { + return nil, err + } + } return nodes, nil } func (gq *GroupQuery) loadUsers(ctx context.Context, query *UserQuery, nodes []*Group, init func(*Group), assign func(*Group, *User)) error { - fks := make([]driver.Value, 0, len(nodes)) - nodeids := make(map[int]*Group) - for i := range nodes { - fks = append(fks, nodes[i].ID) - nodeids[nodes[i].ID] = nodes[i] + edgeIDs := make([]driver.Value, len(nodes)) + byID := make(map[int]*Group) + nids := make(map[int]map[*Group]struct{}) + for i, node := range nodes { + edgeIDs[i] = node.ID + byID[node.ID] = node if init != nil { - init(nodes[i]) + init(node) } } - if len(query.ctx.Fields) > 0 { - query.ctx.AppendFieldOnce(user.FieldGroupUsers) + query.Where(func(s *sql.Selector) { + joinT := sql.Table(group.UsersTable) + s.Join(joinT).On(s.C(user.FieldID), joinT.C(group.UsersPrimaryKey[1])) + s.Where(sql.InValues(joinT.C(group.UsersPrimaryKey[0]), edgeIDs...)) + columns := s.SelectedColumns() + s.Select(joinT.C(group.UsersPrimaryKey[0])) + s.AppendSelect(columns...) + s.SetDistinct(false) + }) + if err := query.prepareQuery(ctx); err != nil { + return err } - query.Where(predicate.User(func(s *sql.Selector) { - s.Where(sql.InValues(s.C(group.UsersColumn), fks...)) - })) - neighbors, err := query.All(ctx) + qr := QuerierFunc(func(ctx context.Context, q Query) (Value, error) { + return query.sqlAll(ctx, func(_ context.Context, spec *sqlgraph.QuerySpec) { + assign := spec.Assign + values := spec.ScanValues + spec.ScanValues = func(columns []string) ([]any, error) { + values, err := values(columns[1:]) + if err != nil { + return nil, err + } + return append([]any{new(sql.NullInt64)}, values...), nil + } + spec.Assign = func(columns []string, values []any) error { + outValue := int(values[0].(*sql.NullInt64).Int64) + inValue := int(values[1].(*sql.NullInt64).Int64) + if nids[inValue] == nil { + nids[inValue] = map[*Group]struct{}{byID[outValue]: {}} + return assign(columns[1:], values[1:]) + } + nids[inValue][byID[outValue]] = struct{}{} + return nil + } + }) + }) + neighbors, err := withInterceptors[[]*User](ctx, query, qr, query.inters) if err != nil { return err } for _, n := range neighbors { - fk := n.GroupUsers - node, ok := nodeids[fk] + nodes, ok := nids[n.ID] if !ok { - return fmt.Errorf(`unexpected referenced foreign-key "group_users" returned %v for node %v`, fk, n.ID) + return fmt.Errorf(`unexpected "users" node returned %v`, n.ID) + } + for kn := range nodes { + assign(kn, n) } - assign(node, n) } return nil } @@ -504,6 +579,36 @@ func (gq *GroupQuery) loadStoragePolicies(ctx context.Context, query *StoragePol } return nil } +func (gq *GroupQuery) loadMembership(ctx context.Context, query *MembershipQuery, nodes []*Group, init func(*Group), assign func(*Group, *Membership)) error { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[int]*Group) + for i := range nodes { + fks = append(fks, nodes[i].ID) + nodeids[nodes[i].ID] = nodes[i] + if init != nil { + init(nodes[i]) + } + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(membership.FieldGroupID) + } + query.Where(predicate.Membership(func(s *sql.Selector) { + s.Where(sql.InValues(s.C(group.MembershipColumn), fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.GroupID + node, ok := nodeids[fk] + if !ok { + return fmt.Errorf(`unexpected referenced foreign-key "group_id" returned %v for node %v`, fk, n) + } + assign(node, n) + } + return nil +} func (gq *GroupQuery) sqlCount(ctx context.Context) (int, error) { _spec := gq.querySpec() diff --git a/ent/group_update.go b/ent/group_update.go index ae734535..75ea761a 100644 --- a/ent/group_update.go +++ b/ent/group_update.go @@ -322,23 +322,27 @@ func (gu *GroupUpdate) sqlSave(ctx context.Context) (n int, err error) { } if gu.mutation.UsersCleared() { edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.O2M, + Rel: sqlgraph.M2M, Inverse: false, Table: group.UsersTable, - Columns: []string{group.UsersColumn}, + Columns: group.UsersPrimaryKey, Bidi: false, Target: &sqlgraph.EdgeTarget{ IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt), }, } + createE := &MembershipCreate{config: gu.config, mutation: newMembershipMutation(gu.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields _spec.Edges.Clear = append(_spec.Edges.Clear, edge) } if nodes := gu.mutation.RemovedUsersIDs(); len(nodes) > 0 && !gu.mutation.UsersCleared() { edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.O2M, + Rel: sqlgraph.M2M, Inverse: false, Table: group.UsersTable, - Columns: []string{group.UsersColumn}, + Columns: group.UsersPrimaryKey, Bidi: false, Target: &sqlgraph.EdgeTarget{ IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt), @@ -347,14 +351,18 @@ func (gu *GroupUpdate) sqlSave(ctx context.Context) (n int, err error) { for _, k := range nodes { edge.Target.Nodes = append(edge.Target.Nodes, k) } + createE := &MembershipCreate{config: gu.config, mutation: newMembershipMutation(gu.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields _spec.Edges.Clear = append(_spec.Edges.Clear, edge) } if nodes := gu.mutation.UsersIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.O2M, + Rel: sqlgraph.M2M, Inverse: false, Table: group.UsersTable, - Columns: []string{group.UsersColumn}, + Columns: group.UsersPrimaryKey, Bidi: false, Target: &sqlgraph.EdgeTarget{ IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt), @@ -363,6 +371,10 @@ func (gu *GroupUpdate) sqlSave(ctx context.Context) (n int, err error) { for _, k := range nodes { edge.Target.Nodes = append(edge.Target.Nodes, k) } + createE := &MembershipCreate{config: gu.config, mutation: newMembershipMutation(gu.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields _spec.Edges.Add = append(_spec.Edges.Add, edge) } if gu.mutation.StoragePoliciesCleared() { @@ -734,23 +746,27 @@ func (guo *GroupUpdateOne) sqlSave(ctx context.Context) (_node *Group, err error } if guo.mutation.UsersCleared() { edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.O2M, + Rel: sqlgraph.M2M, Inverse: false, Table: group.UsersTable, - Columns: []string{group.UsersColumn}, + Columns: group.UsersPrimaryKey, Bidi: false, Target: &sqlgraph.EdgeTarget{ IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt), }, } + createE := &MembershipCreate{config: guo.config, mutation: newMembershipMutation(guo.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields _spec.Edges.Clear = append(_spec.Edges.Clear, edge) } if nodes := guo.mutation.RemovedUsersIDs(); len(nodes) > 0 && !guo.mutation.UsersCleared() { edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.O2M, + Rel: sqlgraph.M2M, Inverse: false, Table: group.UsersTable, - Columns: []string{group.UsersColumn}, + Columns: group.UsersPrimaryKey, Bidi: false, Target: &sqlgraph.EdgeTarget{ IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt), @@ -759,14 +775,18 @@ func (guo *GroupUpdateOne) sqlSave(ctx context.Context) (_node *Group, err error for _, k := range nodes { edge.Target.Nodes = append(edge.Target.Nodes, k) } + createE := &MembershipCreate{config: guo.config, mutation: newMembershipMutation(guo.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields _spec.Edges.Clear = append(_spec.Edges.Clear, edge) } if nodes := guo.mutation.UsersIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.O2M, + Rel: sqlgraph.M2M, Inverse: false, Table: group.UsersTable, - Columns: []string{group.UsersColumn}, + Columns: group.UsersPrimaryKey, Bidi: false, Target: &sqlgraph.EdgeTarget{ IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt), @@ -775,6 +795,10 @@ func (guo *GroupUpdateOne) sqlSave(ctx context.Context) (_node *Group, err error for _, k := range nodes { edge.Target.Nodes = append(edge.Target.Nodes, k) } + createE := &MembershipCreate{config: guo.config, mutation: newMembershipMutation(guo.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields _spec.Edges.Add = append(_spec.Edges.Add, edge) } if guo.mutation.StoragePoliciesCleared() { diff --git a/ent/hook/hook.go b/ent/hook/hook.go index 29b3f1fc..32050555 100644 --- a/ent/hook/hook.go +++ b/ent/hook/hook.go @@ -69,6 +69,18 @@ func (f GroupFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.GroupMutation", m) } +// The MembershipFunc type is an adapter to allow the use of ordinary +// function as Membership mutator. +type MembershipFunc func(context.Context, *ent.MembershipMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f MembershipFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.MembershipMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.MembershipMutation", m) +} + // The MetadataFunc type is an adapter to allow the use of ordinary // function as Metadata mutator. type MetadataFunc func(context.Context, *ent.MetadataMutation) (ent.Value, error) diff --git a/ent/intercept/intercept.go b/ent/intercept/intercept.go index da350367..2ddb7e7a 100644 --- a/ent/intercept/intercept.go +++ b/ent/intercept/intercept.go @@ -13,6 +13,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/file" "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/membership" "github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/passkey" @@ -215,6 +216,33 @@ func (f TraverseGroup) Traverse(ctx context.Context, q ent.Query) error { return fmt.Errorf("unexpected query type %T. expect *ent.GroupQuery", q) } +// The MembershipFunc type is an adapter to allow the use of ordinary function as a Querier. +type MembershipFunc func(context.Context, *ent.MembershipQuery) (ent.Value, error) + +// Query calls f(ctx, q). +func (f MembershipFunc) Query(ctx context.Context, q ent.Query) (ent.Value, error) { + if q, ok := q.(*ent.MembershipQuery); ok { + return f(ctx, q) + } + return nil, fmt.Errorf("unexpected query type %T. expect *ent.MembershipQuery", q) +} + +// The TraverseMembership type is an adapter to allow the use of ordinary function as Traverser. +type TraverseMembership func(context.Context, *ent.MembershipQuery) error + +// Intercept is a dummy implementation of Intercept that returns the next Querier in the pipeline. +func (f TraverseMembership) Intercept(next ent.Querier) ent.Querier { + return next +} + +// Traverse calls f(ctx, q). +func (f TraverseMembership) Traverse(ctx context.Context, q ent.Query) error { + if q, ok := q.(*ent.MembershipQuery); ok { + return f(ctx, q) + } + return fmt.Errorf("unexpected query type %T. expect *ent.MembershipQuery", q) +} + // The MetadataFunc type is an adapter to allow the use of ordinary function as a Querier. type MetadataFunc func(context.Context, *ent.MetadataQuery) (ent.Value, error) @@ -444,6 +472,8 @@ func NewQuery(q ent.Query) (Query, error) { return &query[*ent.FileQuery, predicate.File, file.OrderOption]{typ: ent.TypeFile, tq: q}, nil case *ent.GroupQuery: return &query[*ent.GroupQuery, predicate.Group, group.OrderOption]{typ: ent.TypeGroup, tq: q}, nil + case *ent.MembershipQuery: + return &query[*ent.MembershipQuery, predicate.Membership, membership.OrderOption]{typ: ent.TypeMembership, tq: q}, nil case *ent.MetadataQuery: return &query[*ent.MetadataQuery, predicate.Metadata, metadata.OrderOption]{typ: ent.TypeMetadata, tq: q}, nil case *ent.NodeQuery: diff --git a/ent/internal/schema.go b/ent/internal/schema.go index 6380a862..5900f534 100644 --- a/ent/internal/schema.go +++ b/ent/internal/schema.go @@ -6,4 +6,4 @@ // Package internal holds a loadable version of the latest schema. package internal -const Schema = "{\"Schema\":\"github.com/cloudreve/Cloudreve/v4/ent/schema\",\"Package\":\"github.com/cloudreve/Cloudreve/v4/ent\",\"Schemas\":[{\"name\":\"DavAccount\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"owner\",\"type\":\"User\",\"field\":\"owner_id\",\"ref_name\":\"dav_accounts\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"uri\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"password\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"options\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.DavAccountProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"DavAccountProps\",\"Ident\":\"types.DavAccountProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"owner_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"owner_id\",\"password\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"DirectLink\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"field\":\"file_id\",\"ref_name\":\"direct_links\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"downloads\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"speed\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Entity\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"ref_name\":\"entities\",\"inverse\":true},{\"name\":\"user\",\"type\":\"User\",\"field\":\"created_by\",\"ref_name\":\"entities\",\"unique\":true,\"inverse\":true},{\"name\":\"storage_policy\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_entities\",\"ref_name\":\"entities\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"source\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"reference_count\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":1,\"default_kind\":2,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage_policy_entities\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"created_by\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"upload_session_id\",\"type\":{\"Type\":4,\"Ident\":\"uuid.UUID\",\"PkgPath\":\"github.com/gofrs/uuid\",\"PkgName\":\"uuid\",\"Nillable\":false,\"RType\":{\"Name\":\"UUID\",\"Ident\":\"uuid.UUID\",\"Kind\":17,\"PkgPath\":\"github.com/gofrs/uuid\",\"Methods\":{\"Bytes\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}]},\"Format\":{\"In\":[{\"Name\":\"State\",\"Ident\":\"fmt.State\",\"Kind\":20,\"PkgPath\":\"fmt\",\"Methods\":null},{\"Name\":\"int32\",\"Ident\":\"int32\",\"Kind\":5,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalText\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"SetVariant\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"SetVersion\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalText\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Variant\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]},\"Version\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"recycle_options\",\"type\":{\"Type\":3,\"Ident\":\"*types.EntityRecycleOption\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"EntityRecycleOption\",\"Ident\":\"types.EntityRecycleOption\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"File\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"owner\",\"type\":\"User\",\"field\":\"owner_id\",\"ref_name\":\"files\",\"unique\":true,\"inverse\":true,\"required\":true},{\"name\":\"storage_policies\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_files\",\"ref_name\":\"files\",\"unique\":true,\"inverse\":true},{\"name\":\"parent\",\"type\":\"File\",\"field\":\"file_children\",\"ref\":{\"name\":\"children\",\"type\":\"File\"},\"unique\":true,\"inverse\":true},{\"name\":\"metadata\",\"type\":\"Metadata\"},{\"name\":\"entities\",\"type\":\"Entity\"},{\"name\":\"shares\",\"type\":\"Share\"},{\"name\":\"direct_links\",\"type\":\"DirectLink\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"owner_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":6,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"primary_entity\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_children\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_symbolic\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.FileProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"FileProps\",\"Ident\":\"types.FileProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage_policy_files\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"file_children\",\"name\"]},{\"fields\":[\"file_children\",\"type\",\"updated_at\"]},{\"fields\":[\"file_children\",\"type\",\"size\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}]},{\"name\":\"Group\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"users\",\"type\":\"User\"},{\"name\":\"storage_policies\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_id\",\"ref_name\":\"groups\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"max_storage\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"speed_limit\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"permissions\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.GroupSetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"GroupSetting\",\"Ident\":\"types.GroupSetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage_policy_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Metadata\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"field\":\"file_id\",\"ref_name\":\"metadata\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"value\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_public\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"file_id\",\"name\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Node\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"storage_policy\",\"type\":\"StoragePolicy\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"node.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"active\",\"V\":\"active\"},{\"N\":\"suspended\",\"V\":\"suspended\"}],\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":6,\"Ident\":\"node.Type\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"master\",\"V\":\"master\"},{\"N\":\"slave\",\"V\":\"slave\"}],\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"server\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"slave_key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"capabilities\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.NodeSetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"NodeSetting\",\"Ident\":\"types.NodeSetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"weight\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Passkey\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"passkey\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"user_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"credential_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"credential\",\"type\":{\"Type\":3,\"Ident\":\"*webauthn.Credential\",\"PkgPath\":\"github.com/go-webauthn/webauthn/webauthn\",\"PkgName\":\"webauthn\",\"Nillable\":true,\"RType\":{\"Name\":\"Credential\",\"Ident\":\"webauthn.Credential\",\"Kind\":22,\"PkgPath\":\"github.com/go-webauthn/webauthn/webauthn\",\"Methods\":{\"Descriptor\":{\"In\":[],\"Out\":[{\"Name\":\"CredentialDescriptor\",\"Ident\":\"protocol.CredentialDescriptor\",\"Kind\":25,\"PkgPath\":\"github.com/go-webauthn/webauthn/protocol\",\"Methods\":null}]},\"Verify\":{\"In\":[{\"Name\":\"Provider\",\"Ident\":\"metadata.Provider\",\"Kind\":20,\"PkgPath\":\"github.com/go-webauthn/webauthn/metadata\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"used_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}}],\"indexes\":[{\"unique\":true,\"fields\":[\"user_id\",\"credential_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Setting\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"unique\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"value\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Share\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"ref_name\":\"shares\",\"unique\":true,\"inverse\":true},{\"name\":\"file\",\"type\":\"File\",\"ref_name\":\"shares\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"password\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"views\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"downloads\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"expires\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"remain_downloads\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.ShareProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"ShareProps\",\"Ident\":\"types.ShareProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"StoragePolicy\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"groups\",\"type\":\"Group\"},{\"name\":\"files\",\"type\":\"File\"},{\"name\":\"entities\",\"type\":\"Entity\"},{\"name\":\"node\",\"type\":\"Node\",\"field\":\"node_id\",\"ref_name\":\"storage_policy\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"server\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"bucket_name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_private\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"access_key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"secret_key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"max_size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"dir_name_rule\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_name_rule\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.PolicySetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"PolicySetting\",\"Ident\":\"types.PolicySetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{\"file_type\":null,\"native_media_processing\":false,\"s3_path_style\":false,\"token\":\"\"},\"default_kind\":22,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"node_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":11,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Task\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_tasks\",\"ref_name\":\"tasks\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"task.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"queued\",\"V\":\"queued\"},{\"N\":\"processing\",\"V\":\"processing\"},{\"N\":\"suspending\",\"V\":\"suspending\"},{\"N\":\"error\",\"V\":\"error\"},{\"N\":\"canceled\",\"V\":\"canceled\"},{\"N\":\"completed\",\"V\":\"completed\"}],\"default\":true,\"default_value\":\"queued\",\"default_kind\":24,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"public_state\",\"type\":{\"Type\":3,\"Ident\":\"*types.TaskPublicState\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"TaskPublicState\",\"Ident\":\"types.TaskPublicState\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"private_state\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"correlation_id\",\"type\":{\"Type\":4,\"Ident\":\"uuid.UUID\",\"PkgPath\":\"github.com/gofrs/uuid\",\"PkgName\":\"uuid\",\"Nillable\":false,\"RType\":{\"Name\":\"UUID\",\"Ident\":\"uuid.UUID\",\"Kind\":17,\"PkgPath\":\"github.com/gofrs/uuid\",\"Methods\":{\"Bytes\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}]},\"Format\":{\"In\":[{\"Name\":\"State\",\"Ident\":\"fmt.State\",\"Kind\":20,\"PkgPath\":\"fmt\",\"Methods\":null},{\"Name\":\"int32\",\"Ident\":\"int32\",\"Kind\":5,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalText\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"SetVariant\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"SetVersion\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalText\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Variant\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]},\"Version\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"optional\":true,\"immutable\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"user_tasks\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"User\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"group\",\"type\":\"Group\",\"field\":\"group_users\",\"ref_name\":\"users\",\"unique\":true,\"inverse\":true,\"required\":true},{\"name\":\"files\",\"type\":\"File\"},{\"name\":\"dav_accounts\",\"type\":\"DavAccount\"},{\"name\":\"shares\",\"type\":\"Share\"},{\"name\":\"passkey\",\"type\":\"Passkey\"},{\"name\":\"tasks\",\"type\":\"Task\"},{\"name\":\"entities\",\"type\":\"Entity\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"email\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":100,\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"nick\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":100,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"password\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"user.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"active\",\"V\":\"active\"},{\"N\":\"inactive\",\"V\":\"inactive\"},{\"N\":\"manual_banned\",\"V\":\"manual_banned\"},{\"N\":\"sys_banned\",\"V\":\"sys_banned\"}],\"default\":true,\"default_value\":\"active\",\"default_kind\":24,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":6,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"two_factor_secret\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"avatar\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.UserSetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"UserSetting\",\"Ident\":\"types.UserSetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"group_users\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]}],\"Features\":[\"intercept\",\"schema/snapshot\",\"sql/upsert\",\"sql/upsert\",\"sql/execquery\"]}" +const Schema = "{\"Schema\":\"github.com/cloudreve/Cloudreve/v4/ent/schema\",\"Package\":\"github.com/cloudreve/Cloudreve/v4/ent\",\"Schemas\":[{\"name\":\"DavAccount\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"owner\",\"type\":\"User\",\"field\":\"owner_id\",\"ref_name\":\"dav_accounts\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"uri\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"password\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"options\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.DavAccountProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"DavAccountProps\",\"Ident\":\"types.DavAccountProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"owner_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"owner_id\",\"password\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"DirectLink\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"field\":\"file_id\",\"ref_name\":\"direct_links\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"downloads\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"speed\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Entity\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"ref_name\":\"entities\",\"inverse\":true},{\"name\":\"user\",\"type\":\"User\",\"field\":\"created_by\",\"ref_name\":\"entities\",\"unique\":true,\"inverse\":true},{\"name\":\"storage_policy\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_entities\",\"ref_name\":\"entities\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"source\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"reference_count\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":1,\"default_kind\":2,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage_policy_entities\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"created_by\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"upload_session_id\",\"type\":{\"Type\":4,\"Ident\":\"uuid.UUID\",\"PkgPath\":\"github.com/gofrs/uuid\",\"PkgName\":\"uuid\",\"Nillable\":false,\"RType\":{\"Name\":\"UUID\",\"Ident\":\"uuid.UUID\",\"Kind\":17,\"PkgPath\":\"github.com/gofrs/uuid\",\"Methods\":{\"Bytes\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}]},\"Format\":{\"In\":[{\"Name\":\"State\",\"Ident\":\"fmt.State\",\"Kind\":20,\"PkgPath\":\"fmt\",\"Methods\":null},{\"Name\":\"int32\",\"Ident\":\"int32\",\"Kind\":5,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalText\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"SetVariant\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"SetVersion\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalText\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Variant\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]},\"Version\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"recycle_options\",\"type\":{\"Type\":3,\"Ident\":\"*types.EntityRecycleOption\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"EntityRecycleOption\",\"Ident\":\"types.EntityRecycleOption\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"File\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"owner\",\"type\":\"User\",\"field\":\"owner_id\",\"ref_name\":\"files\",\"unique\":true,\"inverse\":true,\"required\":true},{\"name\":\"storage_policies\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_files\",\"ref_name\":\"files\",\"unique\":true,\"inverse\":true},{\"name\":\"parent\",\"type\":\"File\",\"field\":\"file_children\",\"ref\":{\"name\":\"children\",\"type\":\"File\"},\"unique\":true,\"inverse\":true},{\"name\":\"metadata\",\"type\":\"Metadata\"},{\"name\":\"entities\",\"type\":\"Entity\"},{\"name\":\"shares\",\"type\":\"Share\"},{\"name\":\"direct_links\",\"type\":\"DirectLink\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"owner_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":6,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"primary_entity\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_children\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_symbolic\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.FileProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"FileProps\",\"Ident\":\"types.FileProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage_policy_files\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"file_children\",\"name\"]},{\"fields\":[\"file_children\",\"type\",\"updated_at\"]},{\"fields\":[\"file_children\",\"type\",\"size\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}]},{\"name\":\"Group\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"users\",\"type\":\"User\",\"through\":{\"N\":\"membership\",\"T\":\"Membership\"}},{\"name\":\"storage_policies\",\"type\":\"StoragePolicy\",\"field\":\"storage_policy_id\",\"ref_name\":\"groups\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"max_storage\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"speed_limit\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"permissions\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.GroupSetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"GroupSetting\",\"Ident\":\"types.GroupSetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage_policy_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Membership\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"unique\":true,\"required\":true},{\"name\":\"group\",\"type\":\"Group\",\"field\":\"group_id\",\"unique\":true,\"required\":true}],\"fields\":[{\"name\":\"user_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"group_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"expires_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"annotations\":{\"Fields\":{\"ID\":[\"group_id\",\"user_id\"],\"StructTag\":null}}},{\"name\":\"Metadata\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"file\",\"type\":\"File\",\"field\":\"file_id\",\"ref_name\":\"metadata\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"value\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_public\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":false,\"default_kind\":1,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}}],\"indexes\":[{\"unique\":true,\"fields\":[\"file_id\",\"name\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Node\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"storage_policy\",\"type\":\"StoragePolicy\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"node.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"active\",\"V\":\"active\"},{\"N\":\"suspended\",\"V\":\"suspended\"}],\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":6,\"Ident\":\"node.Type\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"master\",\"V\":\"master\"},{\"N\":\"slave\",\"V\":\"slave\"}],\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"server\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"slave_key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"capabilities\",\"type\":{\"Type\":5,\"Ident\":\"*boolset.BooleanSet\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"PkgName\":\"boolset\",\"Nillable\":true,\"RType\":{\"Name\":\"BooleanSet\",\"Ident\":\"boolset.BooleanSet\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/pkg/boolset\",\"Methods\":{\"Enabled\":{\"In\":[{\"Name\":\"int\",\"Ident\":\"int\",\"Kind\":2,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"bool\",\"Ident\":\"bool\",\"Kind\":1,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.NodeSetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"NodeSetting\",\"Ident\":\"types.NodeSetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"weight\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Passkey\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_id\",\"ref_name\":\"passkey\",\"unique\":true,\"inverse\":true,\"required\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"user_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"credential_id\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"credential\",\"type\":{\"Type\":3,\"Ident\":\"*webauthn.Credential\",\"PkgPath\":\"github.com/go-webauthn/webauthn/webauthn\",\"PkgName\":\"webauthn\",\"Nillable\":true,\"RType\":{\"Name\":\"Credential\",\"Ident\":\"webauthn.Credential\",\"Kind\":22,\"PkgPath\":\"github.com/go-webauthn/webauthn/webauthn\",\"Methods\":{\"Descriptor\":{\"In\":[],\"Out\":[{\"Name\":\"CredentialDescriptor\",\"Ident\":\"protocol.CredentialDescriptor\",\"Kind\":25,\"PkgPath\":\"github.com/go-webauthn/webauthn/protocol\",\"Methods\":null}]},\"Verify\":{\"In\":[{\"Name\":\"Provider\",\"Ident\":\"metadata.Provider\",\"Kind\":20,\"PkgPath\":\"github.com/go-webauthn/webauthn/metadata\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"used_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}}],\"indexes\":[{\"unique\":true,\"fields\":[\"user_id\",\"credential_id\"]}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Setting\",\"config\":{\"Table\":\"\"},\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"unique\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"value\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Share\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"ref_name\":\"shares\",\"unique\":true,\"inverse\":true},{\"name\":\"file\",\"type\":\"File\",\"ref_name\":\"shares\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"password\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"views\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"downloads\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":2,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"expires\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"remain_downloads\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"props\",\"type\":{\"Type\":3,\"Ident\":\"*types.ShareProps\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"ShareProps\",\"Ident\":\"types.ShareProps\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"StoragePolicy\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"groups\",\"type\":\"Group\"},{\"name\":\"files\",\"type\":\"File\"},{\"name\":\"entities\",\"type\":\"Entity\"},{\"name\":\"node\",\"type\":\"Node\",\"field\":\"node_id\",\"ref_name\":\"storage_policy\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"type\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"server\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"bucket_name\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"is_private\",\"type\":{\"Type\":1,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"access_key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"secret_key\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"max_size\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"dir_name_rule\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":8,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"file_name_rule\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":9,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.PolicySetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"PolicySetting\",\"Ident\":\"types.PolicySetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{\"file_type\":null,\"native_media_processing\":false,\"s3_path_style\":false,\"token\":\"\"},\"default_kind\":22,\"position\":{\"Index\":10,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"node_id\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":11,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"Task\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"user\",\"type\":\"User\",\"field\":\"user_tasks\",\"ref_name\":\"tasks\",\"unique\":true,\"inverse\":true}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"type\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"task.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"queued\",\"V\":\"queued\"},{\"N\":\"processing\",\"V\":\"processing\"},{\"N\":\"suspending\",\"V\":\"suspending\"},{\"N\":\"error\",\"V\":\"error\"},{\"N\":\"canceled\",\"V\":\"canceled\"},{\"N\":\"completed\",\"V\":\"completed\"}],\"default\":true,\"default_value\":\"queued\",\"default_kind\":24,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"public_state\",\"type\":{\"Type\":3,\"Ident\":\"*types.TaskPublicState\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"TaskPublicState\",\"Ident\":\"types.TaskPublicState\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"private_state\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":2147483647,\"optional\":true,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"correlation_id\",\"type\":{\"Type\":4,\"Ident\":\"uuid.UUID\",\"PkgPath\":\"github.com/gofrs/uuid\",\"PkgName\":\"uuid\",\"Nillable\":false,\"RType\":{\"Name\":\"UUID\",\"Ident\":\"uuid.UUID\",\"Kind\":17,\"PkgPath\":\"github.com/gofrs/uuid\",\"Methods\":{\"Bytes\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}]},\"Format\":{\"In\":[{\"Name\":\"State\",\"Ident\":\"fmt.State\",\"Kind\":20,\"PkgPath\":\"fmt\",\"Methods\":null},{\"Name\":\"int32\",\"Ident\":\"int32\",\"Kind\":5,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"MarshalBinary\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"MarshalText\":{\"In\":[],\"Out\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Scan\":{\"In\":[{\"Name\":\"\",\"Ident\":\"interface {}\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"SetVariant\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"SetVersion\":{\"In\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[]},\"String\":{\"In\":[],\"Out\":[{\"Name\":\"string\",\"Ident\":\"string\",\"Kind\":24,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalBinary\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"UnmarshalText\":{\"In\":[{\"Name\":\"\",\"Ident\":\"[]uint8\",\"Kind\":23,\"PkgPath\":\"\",\"Methods\":null}],\"Out\":[{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Value\":{\"In\":[],\"Out\":[{\"Name\":\"Value\",\"Ident\":\"driver.Value\",\"Kind\":20,\"PkgPath\":\"database/sql/driver\",\"Methods\":null},{\"Name\":\"error\",\"Ident\":\"error\",\"Kind\":20,\"PkgPath\":\"\",\"Methods\":null}]},\"Variant\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]},\"Version\":{\"In\":[],\"Out\":[{\"Name\":\"uint8\",\"Ident\":\"uint8\",\"Kind\":8,\"PkgPath\":\"\",\"Methods\":null}]}}}},\"optional\":true,\"immutable\":true,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"user_tasks\",\"type\":{\"Type\":12,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]},{\"name\":\"User\",\"config\":{\"Table\":\"\"},\"edges\":[{\"name\":\"group\",\"type\":\"Group\",\"ref_name\":\"users\",\"through\":{\"N\":\"membership\",\"T\":\"Membership\"},\"inverse\":true},{\"name\":\"files\",\"type\":\"File\"},{\"name\":\"dav_accounts\",\"type\":\"DavAccount\"},{\"name\":\"shares\",\"type\":\"Share\"},{\"name\":\"passkey\",\"type\":\"Passkey\"},{\"name\":\"tasks\",\"type\":\"Task\"},{\"name\":\"entities\",\"type\":\"Entity\"}],\"fields\":[{\"name\":\"created_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"immutable\":true,\"position\":{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"updated_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_kind\":19,\"update_default\":true,\"position\":{\"Index\":1,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"deleted_at\",\"type\":{\"Type\":2,\"Ident\":\"\",\"PkgPath\":\"time\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"nillable\":true,\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":true,\"MixinIndex\":0},\"schema_type\":{\"mysql\":\"datetime\"}},{\"name\":\"email\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":100,\"unique\":true,\"validators\":1,\"position\":{\"Index\":0,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"nick\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"size\":100,\"validators\":1,\"position\":{\"Index\":1,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"password\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":2,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"status\",\"type\":{\"Type\":6,\"Ident\":\"user.Status\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"enums\":[{\"N\":\"active\",\"V\":\"active\"},{\"N\":\"inactive\",\"V\":\"inactive\"},{\"N\":\"manual_banned\",\"V\":\"manual_banned\"},{\"N\":\"sys_banned\",\"V\":\"sys_banned\"}],\"default\":true,\"default_value\":\"active\",\"default_kind\":24,\"position\":{\"Index\":3,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"storage\",\"type\":{\"Type\":13,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"default\":true,\"default_value\":0,\"default_kind\":6,\"position\":{\"Index\":4,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"two_factor_secret\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":5,\"MixedIn\":false,\"MixinIndex\":0},\"sensitive\":true},{\"name\":\"avatar\",\"type\":{\"Type\":7,\"Ident\":\"\",\"PkgPath\":\"\",\"PkgName\":\"\",\"Nillable\":false,\"RType\":null},\"optional\":true,\"position\":{\"Index\":6,\"MixedIn\":false,\"MixinIndex\":0}},{\"name\":\"settings\",\"type\":{\"Type\":3,\"Ident\":\"*types.UserSetting\",\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"PkgName\":\"types\",\"Nillable\":true,\"RType\":{\"Name\":\"UserSetting\",\"Ident\":\"types.UserSetting\",\"Kind\":22,\"PkgPath\":\"github.com/cloudreve/Cloudreve/v4/inventory/types\",\"Methods\":{}}},\"optional\":true,\"default\":true,\"default_value\":{},\"default_kind\":22,\"position\":{\"Index\":7,\"MixedIn\":false,\"MixinIndex\":0}}],\"hooks\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}],\"interceptors\":[{\"Index\":0,\"MixedIn\":true,\"MixinIndex\":0}]}],\"Features\":[\"intercept\",\"schema/snapshot\",\"sql/upsert\",\"sql/upsert\",\"sql/execquery\"]}" diff --git a/ent/membership.go b/ent/membership.go new file mode 100644 index 00000000..b730478e --- /dev/null +++ b/ent/membership.go @@ -0,0 +1,195 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "fmt" + "strings" + "time" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" + "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/membership" + "github.com/cloudreve/Cloudreve/v4/ent/user" +) + +// Membership is the model entity for the Membership schema. +type Membership struct { + config `json:"-"` + // UserID holds the value of the "user_id" field. + UserID int `json:"user_id,omitempty"` + // GroupID holds the value of the "group_id" field. + GroupID int `json:"group_id,omitempty"` + // CreatedAt holds the value of the "created_at" field. + CreatedAt time.Time `json:"created_at,omitempty"` + // ExpiresAt holds the value of the "expires_at" field. + ExpiresAt *time.Time `json:"expires_at,omitempty"` + // Edges holds the relations/edges for other nodes in the graph. + // The values are being populated by the MembershipQuery when eager-loading is set. + Edges MembershipEdges `json:"edges"` + selectValues sql.SelectValues +} + +// MembershipEdges holds the relations/edges for other nodes in the graph. +type MembershipEdges struct { + // User holds the value of the user edge. + User *User `json:"user,omitempty"` + // Group holds the value of the group edge. + Group *Group `json:"group,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 MembershipEdges) UserOrErr() (*User, error) { + if e.loadedTypes[0] { + if e.User == nil { + // Edge was loaded but was not found. + return nil, &NotFoundError{label: user.Label} + } + return e.User, nil + } + return nil, &NotLoadedError{edge: "user"} +} + +// GroupOrErr returns the Group value or an error if the edge +// was not loaded in eager-loading, or loaded but was not found. +func (e MembershipEdges) GroupOrErr() (*Group, error) { + if e.loadedTypes[1] { + if e.Group == nil { + // Edge was loaded but was not found. + return nil, &NotFoundError{label: group.Label} + } + return e.Group, nil + } + return nil, &NotLoadedError{edge: "group"} +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*Membership) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case membership.FieldUserID, membership.FieldGroupID: + values[i] = new(sql.NullInt64) + case membership.FieldCreatedAt, membership.FieldExpiresAt: + 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 Membership fields. +func (m *Membership) 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 membership.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 = int(value.Int64) + } + case membership.FieldGroupID: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field group_id", values[i]) + } else if value.Valid { + m.GroupID = int(value.Int64) + } + case membership.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 membership.FieldExpiresAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field expires_at", values[i]) + } else if value.Valid { + m.ExpiresAt = new(time.Time) + *m.ExpiresAt = value.Time + } + default: + m.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the Membership. +// This includes values selected through modifiers, order, etc. +func (m *Membership) Value(name string) (ent.Value, error) { + return m.selectValues.Get(name) +} + +// QueryUser queries the "user" edge of the Membership entity. +func (m *Membership) QueryUser() *UserQuery { + return NewMembershipClient(m.config).QueryUser(m) +} + +// QueryGroup queries the "group" edge of the Membership entity. +func (m *Membership) QueryGroup() *GroupQuery { + return NewMembershipClient(m.config).QueryGroup(m) +} + +// Update returns a builder for updating this Membership. +// Note that you need to call Membership.Unwrap() before calling this method if this Membership +// was returned from a transaction, and the transaction was committed or rolled back. +func (m *Membership) Update() *MembershipUpdateOne { + return NewMembershipClient(m.config).UpdateOne(m) +} + +// Unwrap unwraps the Membership 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 *Membership) Unwrap() *Membership { + _tx, ok := m.config.driver.(*txDriver) + if !ok { + panic("ent: Membership is not a transactional entity") + } + m.config.driver = _tx.drv + return m +} + +// String implements the fmt.Stringer. +func (m *Membership) String() string { + var builder strings.Builder + builder.WriteString("Membership(") + builder.WriteString("user_id=") + builder.WriteString(fmt.Sprintf("%v", m.UserID)) + builder.WriteString(", ") + builder.WriteString("group_id=") + builder.WriteString(fmt.Sprintf("%v", m.GroupID)) + builder.WriteString(", ") + builder.WriteString("created_at=") + builder.WriteString(m.CreatedAt.Format(time.ANSIC)) + builder.WriteString(", ") + if v := m.ExpiresAt; v != nil { + builder.WriteString("expires_at=") + builder.WriteString(v.Format(time.ANSIC)) + } + builder.WriteByte(')') + return builder.String() +} + +// SetUser manually set the edge as loaded state. +func (e *Membership) SetUser(v *User) { + e.Edges.User = v + e.Edges.loadedTypes[0] = true +} + +// SetGroup manually set the edge as loaded state. +func (e *Membership) SetGroup(v *Group) { + e.Edges.Group = v + e.Edges.loadedTypes[1] = true +} + +// Memberships is a parsable slice of Membership. +type Memberships []*Membership diff --git a/ent/membership/membership.go b/ent/membership/membership.go new file mode 100644 index 00000000..40f319bf --- /dev/null +++ b/ent/membership/membership.go @@ -0,0 +1,121 @@ +// Code generated by ent, DO NOT EDIT. + +package membership + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" +) + +const ( + // Label holds the string label denoting the membership type in the database. + Label = "membership" + // FieldUserID holds the string denoting the user_id field in the database. + FieldUserID = "user_id" + // FieldGroupID holds the string denoting the group_id field in the database. + FieldGroupID = "group_id" + // FieldCreatedAt holds the string denoting the created_at field in the database. + FieldCreatedAt = "created_at" + // FieldExpiresAt holds the string denoting the expires_at field in the database. + FieldExpiresAt = "expires_at" + // EdgeUser holds the string denoting the user edge name in mutations. + EdgeUser = "user" + // EdgeGroup holds the string denoting the group edge name in mutations. + EdgeGroup = "group" + // UserFieldID holds the string denoting the ID field of the User. + UserFieldID = "id" + // GroupFieldID holds the string denoting the ID field of the Group. + GroupFieldID = "id" + // Table holds the table name of the membership in the database. + Table = "memberships" + // UserTable is the table that holds the user relation/edge. + UserTable = "memberships" + // UserInverseTable is the table name for the User entity. + // It exists in this package in order to avoid circular dependency with the "user" package. + UserInverseTable = "users" + // UserColumn is the table column denoting the user relation/edge. + UserColumn = "user_id" + // GroupTable is the table that holds the group relation/edge. + GroupTable = "memberships" + // GroupInverseTable is the table name for the Group entity. + // It exists in this package in order to avoid circular dependency with the "group" package. + GroupInverseTable = "groups" + // GroupColumn is the table column denoting the group relation/edge. + GroupColumn = "group_id" +) + +// Columns holds all SQL columns for membership fields. +var Columns = []string{ + FieldUserID, + FieldGroupID, + FieldCreatedAt, + FieldExpiresAt, +} + +// 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 +} + +var ( + // DefaultCreatedAt holds the default value on creation for the "created_at" field. + DefaultCreatedAt func() time.Time +) + +// OrderOption defines the ordering options for the Membership queries. +type OrderOption func(*sql.Selector) + +// ByUserID orders the results by the user_id field. +func ByUserID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldUserID, opts...).ToFunc() +} + +// ByGroupID orders the results by the group_id field. +func ByGroupID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldGroupID, opts...).ToFunc() +} + +// ByCreatedAt orders the results by the created_at field. +func ByCreatedAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldCreatedAt, opts...).ToFunc() +} + +// ByExpiresAt orders the results by the expires_at field. +func ByExpiresAt(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldExpiresAt, opts...).ToFunc() +} + +// ByUserField orders the results by user field. +func ByUserField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newUserStep(), sql.OrderByField(field, opts...)) + } +} + +// ByGroupField orders the results by group field. +func ByGroupField(field string, opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newGroupStep(), sql.OrderByField(field, opts...)) + } +} +func newUserStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, UserColumn), + sqlgraph.To(UserInverseTable, UserFieldID), + sqlgraph.Edge(sqlgraph.M2O, false, UserTable, UserColumn), + ) +} +func newGroupStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, GroupColumn), + sqlgraph.To(GroupInverseTable, GroupFieldID), + sqlgraph.Edge(sqlgraph.M2O, false, GroupTable, GroupColumn), + ) +} diff --git a/ent/membership/where.go b/ent/membership/where.go new file mode 100644 index 00000000..cb9fded6 --- /dev/null +++ b/ent/membership/where.go @@ -0,0 +1,222 @@ +// Code generated by ent, DO NOT EDIT. + +package membership + +import ( + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/cloudreve/Cloudreve/v4/ent/predicate" +) + +// UserID applies equality check predicate on the "user_id" field. It's identical to UserIDEQ. +func UserID(v int) predicate.Membership { + return predicate.Membership(sql.FieldEQ(FieldUserID, v)) +} + +// GroupID applies equality check predicate on the "group_id" field. It's identical to GroupIDEQ. +func GroupID(v int) predicate.Membership { + return predicate.Membership(sql.FieldEQ(FieldGroupID, v)) +} + +// CreatedAt applies equality check predicate on the "created_at" field. It's identical to CreatedAtEQ. +func CreatedAt(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldEQ(FieldCreatedAt, v)) +} + +// ExpiresAt applies equality check predicate on the "expires_at" field. It's identical to ExpiresAtEQ. +func ExpiresAt(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldEQ(FieldExpiresAt, v)) +} + +// UserIDEQ applies the EQ predicate on the "user_id" field. +func UserIDEQ(v int) predicate.Membership { + return predicate.Membership(sql.FieldEQ(FieldUserID, v)) +} + +// UserIDNEQ applies the NEQ predicate on the "user_id" field. +func UserIDNEQ(v int) predicate.Membership { + return predicate.Membership(sql.FieldNEQ(FieldUserID, v)) +} + +// UserIDIn applies the In predicate on the "user_id" field. +func UserIDIn(vs ...int) predicate.Membership { + return predicate.Membership(sql.FieldIn(FieldUserID, vs...)) +} + +// UserIDNotIn applies the NotIn predicate on the "user_id" field. +func UserIDNotIn(vs ...int) predicate.Membership { + return predicate.Membership(sql.FieldNotIn(FieldUserID, vs...)) +} + +// GroupIDEQ applies the EQ predicate on the "group_id" field. +func GroupIDEQ(v int) predicate.Membership { + return predicate.Membership(sql.FieldEQ(FieldGroupID, v)) +} + +// GroupIDNEQ applies the NEQ predicate on the "group_id" field. +func GroupIDNEQ(v int) predicate.Membership { + return predicate.Membership(sql.FieldNEQ(FieldGroupID, v)) +} + +// GroupIDIn applies the In predicate on the "group_id" field. +func GroupIDIn(vs ...int) predicate.Membership { + return predicate.Membership(sql.FieldIn(FieldGroupID, vs...)) +} + +// GroupIDNotIn applies the NotIn predicate on the "group_id" field. +func GroupIDNotIn(vs ...int) predicate.Membership { + return predicate.Membership(sql.FieldNotIn(FieldGroupID, vs...)) +} + +// CreatedAtEQ applies the EQ predicate on the "created_at" field. +func CreatedAtEQ(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldEQ(FieldCreatedAt, v)) +} + +// CreatedAtNEQ applies the NEQ predicate on the "created_at" field. +func CreatedAtNEQ(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldNEQ(FieldCreatedAt, v)) +} + +// CreatedAtIn applies the In predicate on the "created_at" field. +func CreatedAtIn(vs ...time.Time) predicate.Membership { + return predicate.Membership(sql.FieldIn(FieldCreatedAt, vs...)) +} + +// CreatedAtNotIn applies the NotIn predicate on the "created_at" field. +func CreatedAtNotIn(vs ...time.Time) predicate.Membership { + return predicate.Membership(sql.FieldNotIn(FieldCreatedAt, vs...)) +} + +// CreatedAtGT applies the GT predicate on the "created_at" field. +func CreatedAtGT(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldGT(FieldCreatedAt, v)) +} + +// CreatedAtGTE applies the GTE predicate on the "created_at" field. +func CreatedAtGTE(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldGTE(FieldCreatedAt, v)) +} + +// CreatedAtLT applies the LT predicate on the "created_at" field. +func CreatedAtLT(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldLT(FieldCreatedAt, v)) +} + +// CreatedAtLTE applies the LTE predicate on the "created_at" field. +func CreatedAtLTE(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldLTE(FieldCreatedAt, v)) +} + +// ExpiresAtEQ applies the EQ predicate on the "expires_at" field. +func ExpiresAtEQ(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldEQ(FieldExpiresAt, v)) +} + +// ExpiresAtNEQ applies the NEQ predicate on the "expires_at" field. +func ExpiresAtNEQ(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldNEQ(FieldExpiresAt, v)) +} + +// ExpiresAtIn applies the In predicate on the "expires_at" field. +func ExpiresAtIn(vs ...time.Time) predicate.Membership { + return predicate.Membership(sql.FieldIn(FieldExpiresAt, vs...)) +} + +// ExpiresAtNotIn applies the NotIn predicate on the "expires_at" field. +func ExpiresAtNotIn(vs ...time.Time) predicate.Membership { + return predicate.Membership(sql.FieldNotIn(FieldExpiresAt, vs...)) +} + +// ExpiresAtGT applies the GT predicate on the "expires_at" field. +func ExpiresAtGT(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldGT(FieldExpiresAt, v)) +} + +// ExpiresAtGTE applies the GTE predicate on the "expires_at" field. +func ExpiresAtGTE(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldGTE(FieldExpiresAt, v)) +} + +// ExpiresAtLT applies the LT predicate on the "expires_at" field. +func ExpiresAtLT(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldLT(FieldExpiresAt, v)) +} + +// ExpiresAtLTE applies the LTE predicate on the "expires_at" field. +func ExpiresAtLTE(v time.Time) predicate.Membership { + return predicate.Membership(sql.FieldLTE(FieldExpiresAt, v)) +} + +// ExpiresAtIsNil applies the IsNil predicate on the "expires_at" field. +func ExpiresAtIsNil() predicate.Membership { + return predicate.Membership(sql.FieldIsNull(FieldExpiresAt)) +} + +// ExpiresAtNotNil applies the NotNil predicate on the "expires_at" field. +func ExpiresAtNotNil() predicate.Membership { + return predicate.Membership(sql.FieldNotNull(FieldExpiresAt)) +} + +// HasUser applies the HasEdge predicate on the "user" edge. +func HasUser() predicate.Membership { + return predicate.Membership(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, UserColumn), + sqlgraph.Edge(sqlgraph.M2O, false, UserTable, UserColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasUserWith applies the HasEdge predicate on the "user" edge with a given conditions (other predicates). +func HasUserWith(preds ...predicate.User) predicate.Membership { + return predicate.Membership(func(s *sql.Selector) { + step := newUserStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// HasGroup applies the HasEdge predicate on the "group" edge. +func HasGroup() predicate.Membership { + return predicate.Membership(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, GroupColumn), + sqlgraph.Edge(sqlgraph.M2O, false, GroupTable, GroupColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasGroupWith applies the HasEdge predicate on the "group" edge with a given conditions (other predicates). +func HasGroupWith(preds ...predicate.Group) predicate.Membership { + return predicate.Membership(func(s *sql.Selector) { + step := newGroupStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.Membership) predicate.Membership { + return predicate.Membership(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.Membership) predicate.Membership { + return predicate.Membership(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.Membership) predicate.Membership { + return predicate.Membership(sql.NotPredicates(p)) +} diff --git a/ent/membership_create.go b/ent/membership_create.go new file mode 100644 index 00000000..f5e5ac2e --- /dev/null +++ b/ent/membership_create.go @@ -0,0 +1,675 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/membership" + "github.com/cloudreve/Cloudreve/v4/ent/user" +) + +// MembershipCreate is the builder for creating a Membership entity. +type MembershipCreate struct { + config + mutation *MembershipMutation + hooks []Hook + conflict []sql.ConflictOption +} + +// SetUserID sets the "user_id" field. +func (mc *MembershipCreate) SetUserID(i int) *MembershipCreate { + mc.mutation.SetUserID(i) + return mc +} + +// SetGroupID sets the "group_id" field. +func (mc *MembershipCreate) SetGroupID(i int) *MembershipCreate { + mc.mutation.SetGroupID(i) + return mc +} + +// SetCreatedAt sets the "created_at" field. +func (mc *MembershipCreate) SetCreatedAt(t time.Time) *MembershipCreate { + mc.mutation.SetCreatedAt(t) + return mc +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (mc *MembershipCreate) SetNillableCreatedAt(t *time.Time) *MembershipCreate { + if t != nil { + mc.SetCreatedAt(*t) + } + return mc +} + +// SetExpiresAt sets the "expires_at" field. +func (mc *MembershipCreate) SetExpiresAt(t time.Time) *MembershipCreate { + mc.mutation.SetExpiresAt(t) + return mc +} + +// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil. +func (mc *MembershipCreate) SetNillableExpiresAt(t *time.Time) *MembershipCreate { + if t != nil { + mc.SetExpiresAt(*t) + } + return mc +} + +// SetUser sets the "user" edge to the User entity. +func (mc *MembershipCreate) SetUser(u *User) *MembershipCreate { + return mc.SetUserID(u.ID) +} + +// SetGroup sets the "group" edge to the Group entity. +func (mc *MembershipCreate) SetGroup(g *Group) *MembershipCreate { + return mc.SetGroupID(g.ID) +} + +// Mutation returns the MembershipMutation object of the builder. +func (mc *MembershipCreate) Mutation() *MembershipMutation { + return mc.mutation +} + +// Save creates the Membership in the database. +func (mc *MembershipCreate) Save(ctx context.Context) (*Membership, error) { + mc.defaults() + return withHooks(ctx, mc.sqlSave, mc.mutation, mc.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (mc *MembershipCreate) SaveX(ctx context.Context) *Membership { + v, err := mc.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (mc *MembershipCreate) Exec(ctx context.Context) error { + _, err := mc.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (mc *MembershipCreate) ExecX(ctx context.Context) { + if err := mc.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (mc *MembershipCreate) defaults() { + if _, ok := mc.mutation.CreatedAt(); !ok { + v := membership.DefaultCreatedAt() + mc.mutation.SetCreatedAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (mc *MembershipCreate) check() error { + if _, ok := mc.mutation.UserID(); !ok { + return &ValidationError{Name: "user_id", err: errors.New(`ent: missing required field "Membership.user_id"`)} + } + if _, ok := mc.mutation.GroupID(); !ok { + return &ValidationError{Name: "group_id", err: errors.New(`ent: missing required field "Membership.group_id"`)} + } + if _, ok := mc.mutation.CreatedAt(); !ok { + return &ValidationError{Name: "created_at", err: errors.New(`ent: missing required field "Membership.created_at"`)} + } + if _, ok := mc.mutation.UserID(); !ok { + return &ValidationError{Name: "user", err: errors.New(`ent: missing required edge "Membership.user"`)} + } + if _, ok := mc.mutation.GroupID(); !ok { + return &ValidationError{Name: "group", err: errors.New(`ent: missing required edge "Membership.group"`)} + } + return nil +} + +func (mc *MembershipCreate) sqlSave(ctx context.Context) (*Membership, error) { + if err := mc.check(); err != nil { + return nil, err + } + _node, _spec := mc.createSpec() + if err := sqlgraph.CreateNode(ctx, mc.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + return _node, nil +} + +func (mc *MembershipCreate) createSpec() (*Membership, *sqlgraph.CreateSpec) { + var ( + _node = &Membership{config: mc.config} + _spec = sqlgraph.NewCreateSpec(membership.Table, nil) + ) + + _spec.OnConflict = mc.conflict + if value, ok := mc.mutation.CreatedAt(); ok { + _spec.SetField(membership.FieldCreatedAt, field.TypeTime, value) + _node.CreatedAt = value + } + if value, ok := mc.mutation.ExpiresAt(); ok { + _spec.SetField(membership.FieldExpiresAt, field.TypeTime, value) + _node.ExpiresAt = &value + } + if nodes := mc.mutation.UserIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: membership.UserTable, + Columns: []string{membership.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.UserID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + if nodes := mc.mutation.GroupIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: membership.GroupTable, + Columns: []string{membership.GroupColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _node.GroupID = nodes[0] + _spec.Edges = append(_spec.Edges, edge) + } + return _node, _spec +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.Membership.Create(). +// SetUserID(v). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.MembershipUpsert) { +// SetUserID(v+v). +// }). +// Exec(ctx) +func (mc *MembershipCreate) OnConflict(opts ...sql.ConflictOption) *MembershipUpsertOne { + mc.conflict = opts + return &MembershipUpsertOne{ + create: mc, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.Membership.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (mc *MembershipCreate) OnConflictColumns(columns ...string) *MembershipUpsertOne { + mc.conflict = append(mc.conflict, sql.ConflictColumns(columns...)) + return &MembershipUpsertOne{ + create: mc, + } +} + +type ( + // MembershipUpsertOne is the builder for "upsert"-ing + // one Membership node. + MembershipUpsertOne struct { + create *MembershipCreate + } + + // MembershipUpsert is the "OnConflict" setter. + MembershipUpsert struct { + *sql.UpdateSet + } +) + +// SetUserID sets the "user_id" field. +func (u *MembershipUpsert) SetUserID(v int) *MembershipUpsert { + u.Set(membership.FieldUserID, v) + return u +} + +// UpdateUserID sets the "user_id" field to the value that was provided on create. +func (u *MembershipUpsert) UpdateUserID() *MembershipUpsert { + u.SetExcluded(membership.FieldUserID) + return u +} + +// SetGroupID sets the "group_id" field. +func (u *MembershipUpsert) SetGroupID(v int) *MembershipUpsert { + u.Set(membership.FieldGroupID, v) + return u +} + +// UpdateGroupID sets the "group_id" field to the value that was provided on create. +func (u *MembershipUpsert) UpdateGroupID() *MembershipUpsert { + u.SetExcluded(membership.FieldGroupID) + return u +} + +// SetCreatedAt sets the "created_at" field. +func (u *MembershipUpsert) SetCreatedAt(v time.Time) *MembershipUpsert { + u.Set(membership.FieldCreatedAt, v) + return u +} + +// UpdateCreatedAt sets the "created_at" field to the value that was provided on create. +func (u *MembershipUpsert) UpdateCreatedAt() *MembershipUpsert { + u.SetExcluded(membership.FieldCreatedAt) + return u +} + +// SetExpiresAt sets the "expires_at" field. +func (u *MembershipUpsert) SetExpiresAt(v time.Time) *MembershipUpsert { + u.Set(membership.FieldExpiresAt, v) + return u +} + +// UpdateExpiresAt sets the "expires_at" field to the value that was provided on create. +func (u *MembershipUpsert) UpdateExpiresAt() *MembershipUpsert { + u.SetExcluded(membership.FieldExpiresAt) + return u +} + +// ClearExpiresAt clears the value of the "expires_at" field. +func (u *MembershipUpsert) ClearExpiresAt() *MembershipUpsert { + u.SetNull(membership.FieldExpiresAt) + return u +} + +// UpdateNewValues updates the mutable fields using the new values that were set on create. +// Using this option is equivalent to using: +// +// client.Membership.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *MembershipUpsertOne) UpdateNewValues() *MembershipUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.Membership.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *MembershipUpsertOne) Ignore() *MembershipUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *MembershipUpsertOne) DoNothing() *MembershipUpsertOne { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the MembershipCreate.OnConflict +// documentation for more info. +func (u *MembershipUpsertOne) Update(set func(*MembershipUpsert)) *MembershipUpsertOne { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&MembershipUpsert{UpdateSet: update}) + })) + return u +} + +// SetUserID sets the "user_id" field. +func (u *MembershipUpsertOne) SetUserID(v int) *MembershipUpsertOne { + return u.Update(func(s *MembershipUpsert) { + s.SetUserID(v) + }) +} + +// UpdateUserID sets the "user_id" field to the value that was provided on create. +func (u *MembershipUpsertOne) UpdateUserID() *MembershipUpsertOne { + return u.Update(func(s *MembershipUpsert) { + s.UpdateUserID() + }) +} + +// SetGroupID sets the "group_id" field. +func (u *MembershipUpsertOne) SetGroupID(v int) *MembershipUpsertOne { + return u.Update(func(s *MembershipUpsert) { + s.SetGroupID(v) + }) +} + +// UpdateGroupID sets the "group_id" field to the value that was provided on create. +func (u *MembershipUpsertOne) UpdateGroupID() *MembershipUpsertOne { + return u.Update(func(s *MembershipUpsert) { + s.UpdateGroupID() + }) +} + +// SetCreatedAt sets the "created_at" field. +func (u *MembershipUpsertOne) SetCreatedAt(v time.Time) *MembershipUpsertOne { + return u.Update(func(s *MembershipUpsert) { + s.SetCreatedAt(v) + }) +} + +// UpdateCreatedAt sets the "created_at" field to the value that was provided on create. +func (u *MembershipUpsertOne) UpdateCreatedAt() *MembershipUpsertOne { + return u.Update(func(s *MembershipUpsert) { + s.UpdateCreatedAt() + }) +} + +// SetExpiresAt sets the "expires_at" field. +func (u *MembershipUpsertOne) SetExpiresAt(v time.Time) *MembershipUpsertOne { + return u.Update(func(s *MembershipUpsert) { + s.SetExpiresAt(v) + }) +} + +// UpdateExpiresAt sets the "expires_at" field to the value that was provided on create. +func (u *MembershipUpsertOne) UpdateExpiresAt() *MembershipUpsertOne { + return u.Update(func(s *MembershipUpsert) { + s.UpdateExpiresAt() + }) +} + +// ClearExpiresAt clears the value of the "expires_at" field. +func (u *MembershipUpsertOne) ClearExpiresAt() *MembershipUpsertOne { + return u.Update(func(s *MembershipUpsert) { + s.ClearExpiresAt() + }) +} + +// Exec executes the query. +func (u *MembershipUpsertOne) Exec(ctx context.Context) error { + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for MembershipCreate.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *MembershipUpsertOne) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} + +// MembershipCreateBulk is the builder for creating many Membership entities in bulk. +type MembershipCreateBulk struct { + config + err error + builders []*MembershipCreate + conflict []sql.ConflictOption +} + +// Save creates the Membership entities in the database. +func (mcb *MembershipCreateBulk) Save(ctx context.Context) ([]*Membership, error) { + if mcb.err != nil { + return nil, mcb.err + } + specs := make([]*sqlgraph.CreateSpec, len(mcb.builders)) + nodes := make([]*Membership, len(mcb.builders)) + mutators := make([]Mutator, len(mcb.builders)) + for i := range mcb.builders { + func(i int, root context.Context) { + builder := mcb.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*MembershipMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, mcb.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + spec.OnConflict = mcb.conflict + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, mcb.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, mcb.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (mcb *MembershipCreateBulk) SaveX(ctx context.Context) []*Membership { + v, err := mcb.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (mcb *MembershipCreateBulk) Exec(ctx context.Context) error { + _, err := mcb.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (mcb *MembershipCreateBulk) ExecX(ctx context.Context) { + if err := mcb.Exec(ctx); err != nil { + panic(err) + } +} + +// OnConflict allows configuring the `ON CONFLICT` / `ON DUPLICATE KEY` clause +// of the `INSERT` statement. For example: +// +// client.Membership.CreateBulk(builders...). +// OnConflict( +// // Update the row with the new values +// // the was proposed for insertion. +// sql.ResolveWithNewValues(), +// ). +// // Override some of the fields with custom +// // update values. +// Update(func(u *ent.MembershipUpsert) { +// SetUserID(v+v). +// }). +// Exec(ctx) +func (mcb *MembershipCreateBulk) OnConflict(opts ...sql.ConflictOption) *MembershipUpsertBulk { + mcb.conflict = opts + return &MembershipUpsertBulk{ + create: mcb, + } +} + +// OnConflictColumns calls `OnConflict` and configures the columns +// as conflict target. Using this option is equivalent to using: +// +// client.Membership.Create(). +// OnConflict(sql.ConflictColumns(columns...)). +// Exec(ctx) +func (mcb *MembershipCreateBulk) OnConflictColumns(columns ...string) *MembershipUpsertBulk { + mcb.conflict = append(mcb.conflict, sql.ConflictColumns(columns...)) + return &MembershipUpsertBulk{ + create: mcb, + } +} + +// MembershipUpsertBulk is the builder for "upsert"-ing +// a bulk of Membership nodes. +type MembershipUpsertBulk struct { + create *MembershipCreateBulk +} + +// UpdateNewValues updates the mutable fields using the new values that +// were set on create. Using this option is equivalent to using: +// +// client.Membership.Create(). +// OnConflict( +// sql.ResolveWithNewValues(), +// ). +// Exec(ctx) +func (u *MembershipUpsertBulk) UpdateNewValues() *MembershipUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithNewValues()) + return u +} + +// Ignore sets each column to itself in case of conflict. +// Using this option is equivalent to using: +// +// client.Membership.Create(). +// OnConflict(sql.ResolveWithIgnore()). +// Exec(ctx) +func (u *MembershipUpsertBulk) Ignore() *MembershipUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWithIgnore()) + return u +} + +// DoNothing configures the conflict_action to `DO NOTHING`. +// Supported only by SQLite and PostgreSQL. +func (u *MembershipUpsertBulk) DoNothing() *MembershipUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.DoNothing()) + return u +} + +// Update allows overriding fields `UPDATE` values. See the MembershipCreateBulk.OnConflict +// documentation for more info. +func (u *MembershipUpsertBulk) Update(set func(*MembershipUpsert)) *MembershipUpsertBulk { + u.create.conflict = append(u.create.conflict, sql.ResolveWith(func(update *sql.UpdateSet) { + set(&MembershipUpsert{UpdateSet: update}) + })) + return u +} + +// SetUserID sets the "user_id" field. +func (u *MembershipUpsertBulk) SetUserID(v int) *MembershipUpsertBulk { + return u.Update(func(s *MembershipUpsert) { + s.SetUserID(v) + }) +} + +// UpdateUserID sets the "user_id" field to the value that was provided on create. +func (u *MembershipUpsertBulk) UpdateUserID() *MembershipUpsertBulk { + return u.Update(func(s *MembershipUpsert) { + s.UpdateUserID() + }) +} + +// SetGroupID sets the "group_id" field. +func (u *MembershipUpsertBulk) SetGroupID(v int) *MembershipUpsertBulk { + return u.Update(func(s *MembershipUpsert) { + s.SetGroupID(v) + }) +} + +// UpdateGroupID sets the "group_id" field to the value that was provided on create. +func (u *MembershipUpsertBulk) UpdateGroupID() *MembershipUpsertBulk { + return u.Update(func(s *MembershipUpsert) { + s.UpdateGroupID() + }) +} + +// SetCreatedAt sets the "created_at" field. +func (u *MembershipUpsertBulk) SetCreatedAt(v time.Time) *MembershipUpsertBulk { + return u.Update(func(s *MembershipUpsert) { + s.SetCreatedAt(v) + }) +} + +// UpdateCreatedAt sets the "created_at" field to the value that was provided on create. +func (u *MembershipUpsertBulk) UpdateCreatedAt() *MembershipUpsertBulk { + return u.Update(func(s *MembershipUpsert) { + s.UpdateCreatedAt() + }) +} + +// SetExpiresAt sets the "expires_at" field. +func (u *MembershipUpsertBulk) SetExpiresAt(v time.Time) *MembershipUpsertBulk { + return u.Update(func(s *MembershipUpsert) { + s.SetExpiresAt(v) + }) +} + +// UpdateExpiresAt sets the "expires_at" field to the value that was provided on create. +func (u *MembershipUpsertBulk) UpdateExpiresAt() *MembershipUpsertBulk { + return u.Update(func(s *MembershipUpsert) { + s.UpdateExpiresAt() + }) +} + +// ClearExpiresAt clears the value of the "expires_at" field. +func (u *MembershipUpsertBulk) ClearExpiresAt() *MembershipUpsertBulk { + return u.Update(func(s *MembershipUpsert) { + s.ClearExpiresAt() + }) +} + +// Exec executes the query. +func (u *MembershipUpsertBulk) Exec(ctx context.Context) error { + if u.create.err != nil { + return u.create.err + } + for i, b := range u.create.builders { + if len(b.conflict) != 0 { + return fmt.Errorf("ent: OnConflict was set for builder %d. Set it on the MembershipCreateBulk instead", i) + } + } + if len(u.create.conflict) == 0 { + return errors.New("ent: missing options for MembershipCreateBulk.OnConflict") + } + return u.create.Exec(ctx) +} + +// ExecX is like Exec, but panics if an error occurs. +func (u *MembershipUpsertBulk) ExecX(ctx context.Context) { + if err := u.create.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/membership_delete.go b/ent/membership_delete.go new file mode 100644 index 00000000..f36b5db6 --- /dev/null +++ b/ent/membership_delete.go @@ -0,0 +1,87 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/cloudreve/Cloudreve/v4/ent/membership" + "github.com/cloudreve/Cloudreve/v4/ent/predicate" +) + +// MembershipDelete is the builder for deleting a Membership entity. +type MembershipDelete struct { + config + hooks []Hook + mutation *MembershipMutation +} + +// Where appends a list predicates to the MembershipDelete builder. +func (md *MembershipDelete) Where(ps ...predicate.Membership) *MembershipDelete { + md.mutation.Where(ps...) + return md +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (md *MembershipDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, md.sqlExec, md.mutation, md.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (md *MembershipDelete) ExecX(ctx context.Context) int { + n, err := md.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (md *MembershipDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(membership.Table, nil) + if ps := md.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, md.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + md.mutation.done = true + return affected, err +} + +// MembershipDeleteOne is the builder for deleting a single Membership entity. +type MembershipDeleteOne struct { + md *MembershipDelete +} + +// Where appends a list predicates to the MembershipDelete builder. +func (mdo *MembershipDeleteOne) Where(ps ...predicate.Membership) *MembershipDeleteOne { + mdo.md.mutation.Where(ps...) + return mdo +} + +// Exec executes the deletion query. +func (mdo *MembershipDeleteOne) Exec(ctx context.Context) error { + n, err := mdo.md.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{membership.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (mdo *MembershipDeleteOne) ExecX(ctx context.Context) { + if err := mdo.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/membership_query.go b/ent/membership_query.go new file mode 100644 index 00000000..5d35f3c0 --- /dev/null +++ b/ent/membership_query.go @@ -0,0 +1,602 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "math" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/membership" + "github.com/cloudreve/Cloudreve/v4/ent/predicate" + "github.com/cloudreve/Cloudreve/v4/ent/user" +) + +// MembershipQuery is the builder for querying Membership entities. +type MembershipQuery struct { + config + ctx *QueryContext + order []membership.OrderOption + inters []Interceptor + predicates []predicate.Membership + withUser *UserQuery + withGroup *GroupQuery + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the MembershipQuery builder. +func (mq *MembershipQuery) Where(ps ...predicate.Membership) *MembershipQuery { + mq.predicates = append(mq.predicates, ps...) + return mq +} + +// Limit the number of records to be returned by this query. +func (mq *MembershipQuery) Limit(limit int) *MembershipQuery { + mq.ctx.Limit = &limit + return mq +} + +// Offset to start from. +func (mq *MembershipQuery) Offset(offset int) *MembershipQuery { + mq.ctx.Offset = &offset + return mq +} + +// 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. +func (mq *MembershipQuery) Unique(unique bool) *MembershipQuery { + mq.ctx.Unique = &unique + return mq +} + +// Order specifies how the records should be ordered. +func (mq *MembershipQuery) Order(o ...membership.OrderOption) *MembershipQuery { + mq.order = append(mq.order, o...) + return mq +} + +// QueryUser chains the current query on the "user" edge. +func (mq *MembershipQuery) QueryUser() *UserQuery { + query := (&UserClient{config: mq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := mq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := mq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(membership.Table, membership.UserColumn, selector), + sqlgraph.To(user.Table, user.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, membership.UserTable, membership.UserColumn), + ) + fromU = sqlgraph.SetNeighbors(mq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// QueryGroup chains the current query on the "group" edge. +func (mq *MembershipQuery) QueryGroup() *GroupQuery { + query := (&GroupClient{config: mq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := mq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := mq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(membership.Table, membership.GroupColumn, selector), + sqlgraph.To(group.Table, group.FieldID), + sqlgraph.Edge(sqlgraph.M2O, false, membership.GroupTable, membership.GroupColumn), + ) + fromU = sqlgraph.SetNeighbors(mq.driver.Dialect(), step) + return fromU, nil + } + return query +} + +// First returns the first Membership entity from the query. +// Returns a *NotFoundError when no Membership was found. +func (mq *MembershipQuery) First(ctx context.Context) (*Membership, error) { + nodes, err := mq.Limit(1).All(setContextOp(ctx, mq.ctx, "First")) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{membership.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (mq *MembershipQuery) FirstX(ctx context.Context) *Membership { + node, err := mq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// Only returns a single Membership entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one Membership entity is found. +// Returns a *NotFoundError when no Membership entities are found. +func (mq *MembershipQuery) Only(ctx context.Context) (*Membership, error) { + nodes, err := mq.Limit(2).All(setContextOp(ctx, mq.ctx, "Only")) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{membership.Label} + default: + return nil, &NotSingularError{membership.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (mq *MembershipQuery) OnlyX(ctx context.Context) *Membership { + node, err := mq.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// All executes the query and returns a list of Memberships. +func (mq *MembershipQuery) All(ctx context.Context) ([]*Membership, error) { + ctx = setContextOp(ctx, mq.ctx, "All") + if err := mq.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*Membership, *MembershipQuery]() + return withInterceptors[[]*Membership](ctx, mq, qr, mq.inters) +} + +// AllX is like All, but panics if an error occurs. +func (mq *MembershipQuery) AllX(ctx context.Context) []*Membership { + nodes, err := mq.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// Count returns the count of the given query. +func (mq *MembershipQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, mq.ctx, "Count") + if err := mq.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, mq, querierCount[*MembershipQuery](), mq.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (mq *MembershipQuery) CountX(ctx context.Context) int { + count, err := mq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (mq *MembershipQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, mq.ctx, "Exist") + switch _, err := mq.First(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (mq *MembershipQuery) ExistX(ctx context.Context) bool { + exist, err := mq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the MembershipQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (mq *MembershipQuery) Clone() *MembershipQuery { + if mq == nil { + return nil + } + return &MembershipQuery{ + config: mq.config, + ctx: mq.ctx.Clone(), + order: append([]membership.OrderOption{}, mq.order...), + inters: append([]Interceptor{}, mq.inters...), + predicates: append([]predicate.Membership{}, mq.predicates...), + withUser: mq.withUser.Clone(), + withGroup: mq.withGroup.Clone(), + // clone intermediate query. + sql: mq.sql.Clone(), + path: mq.path, + } +} + +// 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. +func (mq *MembershipQuery) WithUser(opts ...func(*UserQuery)) *MembershipQuery { + query := (&UserClient{config: mq.config}).Query() + for _, opt := range opts { + opt(query) + } + mq.withUser = query + return mq +} + +// 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. +func (mq *MembershipQuery) WithGroup(opts ...func(*GroupQuery)) *MembershipQuery { + query := (&GroupClient{config: mq.config}).Query() + for _, opt := range opts { + opt(query) + } + mq.withGroup = query + return mq +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// UserID int `json:"user_id,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.Membership.Query(). +// GroupBy(membership.FieldUserID). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (mq *MembershipQuery) GroupBy(field string, fields ...string) *MembershipGroupBy { + mq.ctx.Fields = append([]string{field}, fields...) + grbuild := &MembershipGroupBy{build: mq} + grbuild.flds = &mq.ctx.Fields + grbuild.label = membership.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// UserID int `json:"user_id,omitempty"` +// } +// +// client.Membership.Query(). +// Select(membership.FieldUserID). +// Scan(ctx, &v) +func (mq *MembershipQuery) Select(fields ...string) *MembershipSelect { + mq.ctx.Fields = append(mq.ctx.Fields, fields...) + sbuild := &MembershipSelect{MembershipQuery: mq} + sbuild.label = membership.Label + sbuild.flds, sbuild.scan = &mq.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a MembershipSelect configured with the given aggregations. +func (mq *MembershipQuery) Aggregate(fns ...AggregateFunc) *MembershipSelect { + return mq.Select().Aggregate(fns...) +} + +func (mq *MembershipQuery) prepareQuery(ctx context.Context) error { + for _, inter := range mq.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, mq); err != nil { + return err + } + } + } + for _, f := range mq.ctx.Fields { + if !membership.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if mq.path != nil { + prev, err := mq.path(ctx) + if err != nil { + return err + } + mq.sql = prev + } + return nil +} + +func (mq *MembershipQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*Membership, error) { + var ( + nodes = []*Membership{} + _spec = mq.querySpec() + loadedTypes = [2]bool{ + mq.withUser != nil, + mq.withGroup != nil, + } + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*Membership).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &Membership{config: mq.config} + nodes = append(nodes, node) + node.Edges.loadedTypes = loadedTypes + return node.assignValues(columns, values) + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, mq.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + if query := mq.withUser; query != nil { + if err := mq.loadUser(ctx, query, nodes, nil, + func(n *Membership, e *User) { n.Edges.User = e }); err != nil { + return nil, err + } + } + if query := mq.withGroup; query != nil { + if err := mq.loadGroup(ctx, query, nodes, nil, + func(n *Membership, e *Group) { n.Edges.Group = e }); err != nil { + return nil, err + } + } + return nodes, nil +} + +func (mq *MembershipQuery) loadUser(ctx context.Context, query *UserQuery, nodes []*Membership, init func(*Membership), assign func(*Membership, *User)) error { + ids := make([]int, 0, len(nodes)) + nodeids := make(map[int][]*Membership) + for i := range nodes { + fk := nodes[i].UserID + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(user.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "user_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} +func (mq *MembershipQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes []*Membership, init func(*Membership), assign func(*Membership, *Group)) error { + ids := make([]int, 0, len(nodes)) + nodeids := make(map[int][]*Membership) + for i := range nodes { + fk := nodes[i].GroupID + if _, ok := nodeids[fk]; !ok { + ids = append(ids, fk) + } + nodeids[fk] = append(nodeids[fk], nodes[i]) + } + if len(ids) == 0 { + return nil + } + query.Where(group.IDIn(ids...)) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + nodes, ok := nodeids[n.ID] + if !ok { + return fmt.Errorf(`unexpected foreign-key "group_id" returned %v`, n.ID) + } + for i := range nodes { + assign(nodes[i], n) + } + } + return nil +} + +func (mq *MembershipQuery) sqlCount(ctx context.Context) (int, error) { + _spec := mq.querySpec() + _spec.Unique = false + _spec.Node.Columns = nil + return sqlgraph.CountNodes(ctx, mq.driver, _spec) +} + +func (mq *MembershipQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(membership.Table, membership.Columns, nil) + _spec.From = mq.sql + if unique := mq.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if mq.path != nil { + _spec.Unique = true + } + if fields := mq.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + for i := range fields { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + if mq.withUser != nil { + _spec.Node.AddColumnOnce(membership.FieldUserID) + } + if mq.withGroup != nil { + _spec.Node.AddColumnOnce(membership.FieldGroupID) + } + } + if ps := mq.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := mq.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := mq.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := mq.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (mq *MembershipQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(mq.driver.Dialect()) + t1 := builder.Table(membership.Table) + columns := mq.ctx.Fields + if len(columns) == 0 { + columns = membership.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if mq.sql != nil { + selector = mq.sql + selector.Select(selector.Columns(columns...)...) + } + if mq.ctx.Unique != nil && *mq.ctx.Unique { + selector.Distinct() + } + for _, p := range mq.predicates { + p(selector) + } + for _, p := range mq.order { + p(selector) + } + if offset := mq.ctx.Offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := mq.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// MembershipGroupBy is the group-by builder for Membership entities. +type MembershipGroupBy struct { + selector + build *MembershipQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (mgb *MembershipGroupBy) Aggregate(fns ...AggregateFunc) *MembershipGroupBy { + mgb.fns = append(mgb.fns, fns...) + return mgb +} + +// Scan applies the selector query and scans the result into the given value. +func (mgb *MembershipGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, mgb.build.ctx, "GroupBy") + if err := mgb.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*MembershipQuery, *MembershipGroupBy](ctx, mgb.build, mgb, mgb.build.inters, v) +} + +func (mgb *MembershipGroupBy) sqlScan(ctx context.Context, root *MembershipQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(mgb.fns)) + for _, fn := range mgb.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*mgb.flds)+len(mgb.fns)) + for _, f := range *mgb.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*mgb.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := mgb.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// MembershipSelect is the builder for selecting fields of Membership entities. +type MembershipSelect struct { + *MembershipQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (ms *MembershipSelect) Aggregate(fns ...AggregateFunc) *MembershipSelect { + ms.fns = append(ms.fns, fns...) + return ms +} + +// Scan applies the selector query and scans the result into the given value. +func (ms *MembershipSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, ms.ctx, "Select") + if err := ms.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*MembershipQuery, *MembershipSelect](ctx, ms.MembershipQuery, ms, ms.inters, v) +} + +func (ms *MembershipSelect) sqlScan(ctx context.Context, root *MembershipQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(ms.fns)) + for _, fn := range ms.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*ms.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := ms.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/ent/membership_update.go b/ent/membership_update.go new file mode 100644 index 00000000..57e3be7d --- /dev/null +++ b/ent/membership_update.go @@ -0,0 +1,510 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/membership" + "github.com/cloudreve/Cloudreve/v4/ent/predicate" + "github.com/cloudreve/Cloudreve/v4/ent/user" +) + +// MembershipUpdate is the builder for updating Membership entities. +type MembershipUpdate struct { + config + hooks []Hook + mutation *MembershipMutation +} + +// Where appends a list predicates to the MembershipUpdate builder. +func (mu *MembershipUpdate) Where(ps ...predicate.Membership) *MembershipUpdate { + mu.mutation.Where(ps...) + return mu +} + +// SetUserID sets the "user_id" field. +func (mu *MembershipUpdate) SetUserID(i int) *MembershipUpdate { + mu.mutation.SetUserID(i) + return mu +} + +// SetNillableUserID sets the "user_id" field if the given value is not nil. +func (mu *MembershipUpdate) SetNillableUserID(i *int) *MembershipUpdate { + if i != nil { + mu.SetUserID(*i) + } + return mu +} + +// SetGroupID sets the "group_id" field. +func (mu *MembershipUpdate) SetGroupID(i int) *MembershipUpdate { + mu.mutation.SetGroupID(i) + return mu +} + +// SetNillableGroupID sets the "group_id" field if the given value is not nil. +func (mu *MembershipUpdate) SetNillableGroupID(i *int) *MembershipUpdate { + if i != nil { + mu.SetGroupID(*i) + } + return mu +} + +// SetCreatedAt sets the "created_at" field. +func (mu *MembershipUpdate) SetCreatedAt(t time.Time) *MembershipUpdate { + mu.mutation.SetCreatedAt(t) + return mu +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (mu *MembershipUpdate) SetNillableCreatedAt(t *time.Time) *MembershipUpdate { + if t != nil { + mu.SetCreatedAt(*t) + } + return mu +} + +// SetExpiresAt sets the "expires_at" field. +func (mu *MembershipUpdate) SetExpiresAt(t time.Time) *MembershipUpdate { + mu.mutation.SetExpiresAt(t) + return mu +} + +// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil. +func (mu *MembershipUpdate) SetNillableExpiresAt(t *time.Time) *MembershipUpdate { + if t != nil { + mu.SetExpiresAt(*t) + } + return mu +} + +// ClearExpiresAt clears the value of the "expires_at" field. +func (mu *MembershipUpdate) ClearExpiresAt() *MembershipUpdate { + mu.mutation.ClearExpiresAt() + return mu +} + +// SetUser sets the "user" edge to the User entity. +func (mu *MembershipUpdate) SetUser(u *User) *MembershipUpdate { + return mu.SetUserID(u.ID) +} + +// SetGroup sets the "group" edge to the Group entity. +func (mu *MembershipUpdate) SetGroup(g *Group) *MembershipUpdate { + return mu.SetGroupID(g.ID) +} + +// Mutation returns the MembershipMutation object of the builder. +func (mu *MembershipUpdate) Mutation() *MembershipMutation { + return mu.mutation +} + +// ClearUser clears the "user" edge to the User entity. +func (mu *MembershipUpdate) ClearUser() *MembershipUpdate { + mu.mutation.ClearUser() + return mu +} + +// ClearGroup clears the "group" edge to the Group entity. +func (mu *MembershipUpdate) ClearGroup() *MembershipUpdate { + mu.mutation.ClearGroup() + return mu +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (mu *MembershipUpdate) Save(ctx context.Context) (int, error) { + return withHooks(ctx, mu.sqlSave, mu.mutation, mu.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (mu *MembershipUpdate) SaveX(ctx context.Context) int { + affected, err := mu.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (mu *MembershipUpdate) Exec(ctx context.Context) error { + _, err := mu.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (mu *MembershipUpdate) ExecX(ctx context.Context) { + if err := mu.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (mu *MembershipUpdate) check() error { + if _, ok := mu.mutation.UserID(); mu.mutation.UserCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "Membership.user"`) + } + if _, ok := mu.mutation.GroupID(); mu.mutation.GroupCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "Membership.group"`) + } + return nil +} + +func (mu *MembershipUpdate) sqlSave(ctx context.Context) (n int, err error) { + if err := mu.check(); err != nil { + return n, err + } + _spec := sqlgraph.NewUpdateSpec(membership.Table, membership.Columns, sqlgraph.NewFieldSpec(membership.FieldGroupID, field.TypeInt), sqlgraph.NewFieldSpec(membership.FieldUserID, field.TypeInt)) + if ps := mu.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := mu.mutation.CreatedAt(); ok { + _spec.SetField(membership.FieldCreatedAt, field.TypeTime, value) + } + if value, ok := mu.mutation.ExpiresAt(); ok { + _spec.SetField(membership.FieldExpiresAt, field.TypeTime, value) + } + if mu.mutation.ExpiresAtCleared() { + _spec.ClearField(membership.FieldExpiresAt, field.TypeTime) + } + if mu.mutation.UserCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: membership.UserTable, + Columns: []string{membership.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := mu.mutation.UserIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: membership.UserTable, + Columns: []string{membership.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if mu.mutation.GroupCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: membership.GroupTable, + Columns: []string{membership.GroupColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeInt), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := mu.mutation.GroupIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: membership.GroupTable, + Columns: []string{membership.GroupColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if n, err = sqlgraph.UpdateNodes(ctx, mu.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{membership.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + mu.mutation.done = true + return n, nil +} + +// MembershipUpdateOne is the builder for updating a single Membership entity. +type MembershipUpdateOne struct { + config + fields []string + hooks []Hook + mutation *MembershipMutation +} + +// SetUserID sets the "user_id" field. +func (muo *MembershipUpdateOne) SetUserID(i int) *MembershipUpdateOne { + muo.mutation.SetUserID(i) + return muo +} + +// SetNillableUserID sets the "user_id" field if the given value is not nil. +func (muo *MembershipUpdateOne) SetNillableUserID(i *int) *MembershipUpdateOne { + if i != nil { + muo.SetUserID(*i) + } + return muo +} + +// SetGroupID sets the "group_id" field. +func (muo *MembershipUpdateOne) SetGroupID(i int) *MembershipUpdateOne { + muo.mutation.SetGroupID(i) + return muo +} + +// SetNillableGroupID sets the "group_id" field if the given value is not nil. +func (muo *MembershipUpdateOne) SetNillableGroupID(i *int) *MembershipUpdateOne { + if i != nil { + muo.SetGroupID(*i) + } + return muo +} + +// SetCreatedAt sets the "created_at" field. +func (muo *MembershipUpdateOne) SetCreatedAt(t time.Time) *MembershipUpdateOne { + muo.mutation.SetCreatedAt(t) + return muo +} + +// SetNillableCreatedAt sets the "created_at" field if the given value is not nil. +func (muo *MembershipUpdateOne) SetNillableCreatedAt(t *time.Time) *MembershipUpdateOne { + if t != nil { + muo.SetCreatedAt(*t) + } + return muo +} + +// SetExpiresAt sets the "expires_at" field. +func (muo *MembershipUpdateOne) SetExpiresAt(t time.Time) *MembershipUpdateOne { + muo.mutation.SetExpiresAt(t) + return muo +} + +// SetNillableExpiresAt sets the "expires_at" field if the given value is not nil. +func (muo *MembershipUpdateOne) SetNillableExpiresAt(t *time.Time) *MembershipUpdateOne { + if t != nil { + muo.SetExpiresAt(*t) + } + return muo +} + +// ClearExpiresAt clears the value of the "expires_at" field. +func (muo *MembershipUpdateOne) ClearExpiresAt() *MembershipUpdateOne { + muo.mutation.ClearExpiresAt() + return muo +} + +// SetUser sets the "user" edge to the User entity. +func (muo *MembershipUpdateOne) SetUser(u *User) *MembershipUpdateOne { + return muo.SetUserID(u.ID) +} + +// SetGroup sets the "group" edge to the Group entity. +func (muo *MembershipUpdateOne) SetGroup(g *Group) *MembershipUpdateOne { + return muo.SetGroupID(g.ID) +} + +// Mutation returns the MembershipMutation object of the builder. +func (muo *MembershipUpdateOne) Mutation() *MembershipMutation { + return muo.mutation +} + +// ClearUser clears the "user" edge to the User entity. +func (muo *MembershipUpdateOne) ClearUser() *MembershipUpdateOne { + muo.mutation.ClearUser() + return muo +} + +// ClearGroup clears the "group" edge to the Group entity. +func (muo *MembershipUpdateOne) ClearGroup() *MembershipUpdateOne { + muo.mutation.ClearGroup() + return muo +} + +// Where appends a list predicates to the MembershipUpdate builder. +func (muo *MembershipUpdateOne) Where(ps ...predicate.Membership) *MembershipUpdateOne { + muo.mutation.Where(ps...) + return muo +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (muo *MembershipUpdateOne) Select(field string, fields ...string) *MembershipUpdateOne { + muo.fields = append([]string{field}, fields...) + return muo +} + +// Save executes the query and returns the updated Membership entity. +func (muo *MembershipUpdateOne) Save(ctx context.Context) (*Membership, error) { + return withHooks(ctx, muo.sqlSave, muo.mutation, muo.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (muo *MembershipUpdateOne) SaveX(ctx context.Context) *Membership { + node, err := muo.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (muo *MembershipUpdateOne) Exec(ctx context.Context) error { + _, err := muo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (muo *MembershipUpdateOne) ExecX(ctx context.Context) { + if err := muo.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (muo *MembershipUpdateOne) check() error { + if _, ok := muo.mutation.UserID(); muo.mutation.UserCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "Membership.user"`) + } + if _, ok := muo.mutation.GroupID(); muo.mutation.GroupCleared() && !ok { + return errors.New(`ent: clearing a required unique edge "Membership.group"`) + } + return nil +} + +func (muo *MembershipUpdateOne) sqlSave(ctx context.Context) (_node *Membership, err error) { + if err := muo.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(membership.Table, membership.Columns, sqlgraph.NewFieldSpec(membership.FieldGroupID, field.TypeInt), sqlgraph.NewFieldSpec(membership.FieldUserID, field.TypeInt)) + if id, ok := muo.mutation.GroupID(); !ok { + return nil, &ValidationError{Name: "group_id", err: errors.New(`ent: missing "Membership.group_id" for update`)} + } else { + _spec.Node.CompositeID[0].Value = id + } + if id, ok := muo.mutation.UserID(); !ok { + return nil, &ValidationError{Name: "user_id", err: errors.New(`ent: missing "Membership.user_id" for update`)} + } else { + _spec.Node.CompositeID[1].Value = id + } + if fields := muo.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, len(fields)) + for i, f := range fields { + if !membership.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + _spec.Node.Columns[i] = f + } + } + if ps := muo.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := muo.mutation.CreatedAt(); ok { + _spec.SetField(membership.FieldCreatedAt, field.TypeTime, value) + } + if value, ok := muo.mutation.ExpiresAt(); ok { + _spec.SetField(membership.FieldExpiresAt, field.TypeTime, value) + } + if muo.mutation.ExpiresAtCleared() { + _spec.ClearField(membership.FieldExpiresAt, field.TypeTime) + } + if muo.mutation.UserCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: membership.UserTable, + Columns: []string{membership.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := muo.mutation.UserIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: membership.UserTable, + Columns: []string{membership.UserColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + if muo.mutation.GroupCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: membership.GroupTable, + Columns: []string{membership.GroupColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeInt), + }, + } + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := muo.mutation.GroupIDs(); len(nodes) > 0 { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2O, + Inverse: false, + Table: membership.GroupTable, + Columns: []string{membership.GroupColumn}, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + _spec.Edges.Add = append(_spec.Edges.Add, edge) + } + _node = &Membership{config: muo.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, muo.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{membership.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + muo.mutation.done = true + return _node, nil +} diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index 8b85556a..017e6276 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -187,6 +187,33 @@ var ( }, }, } + // MembershipsColumns holds the columns for the "memberships" table. + MembershipsColumns = []*schema.Column{ + {Name: "created_at", Type: field.TypeTime}, + {Name: "expires_at", Type: field.TypeTime, Nullable: true}, + {Name: "user_id", Type: field.TypeInt}, + {Name: "group_id", Type: field.TypeInt}, + } + // MembershipsTable holds the schema information for the "memberships" table. + MembershipsTable = &schema.Table{ + Name: "memberships", + Columns: MembershipsColumns, + PrimaryKey: []*schema.Column{MembershipsColumns[3], MembershipsColumns[2]}, + ForeignKeys: []*schema.ForeignKey{ + { + Symbol: "memberships_users_user", + Columns: []*schema.Column{MembershipsColumns[2]}, + RefColumns: []*schema.Column{UsersColumns[0]}, + OnDelete: schema.NoAction, + }, + { + Symbol: "memberships_groups_group", + Columns: []*schema.Column{MembershipsColumns[3]}, + RefColumns: []*schema.Column{GroupsColumns[0]}, + OnDelete: schema.NoAction, + }, + }, + } // MetadataColumns holds the columns for the "metadata" table. MetadataColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, @@ -397,21 +424,12 @@ var ( {Name: "two_factor_secret", Type: field.TypeString, Nullable: true}, {Name: "avatar", Type: field.TypeString, Nullable: true}, {Name: "settings", Type: field.TypeJSON, Nullable: true}, - {Name: "group_users", Type: field.TypeInt}, } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ Name: "users", Columns: UsersColumns, PrimaryKey: []*schema.Column{UsersColumns[0]}, - ForeignKeys: []*schema.ForeignKey{ - { - Symbol: "users_groups_users", - Columns: []*schema.Column{UsersColumns[12]}, - RefColumns: []*schema.Column{GroupsColumns[0]}, - OnDelete: schema.NoAction, - }, - }, } // FileEntitiesColumns holds the columns for the "file_entities" table. FileEntitiesColumns = []*schema.Column{ @@ -445,6 +463,7 @@ var ( EntitiesTable, FilesTable, GroupsTable, + MembershipsTable, MetadataTable, NodesTable, PasskeysTable, @@ -466,13 +485,14 @@ func init() { FilesTable.ForeignKeys[1].RefTable = StoragePoliciesTable FilesTable.ForeignKeys[2].RefTable = UsersTable GroupsTable.ForeignKeys[0].RefTable = StoragePoliciesTable + MembershipsTable.ForeignKeys[0].RefTable = UsersTable + MembershipsTable.ForeignKeys[1].RefTable = GroupsTable MetadataTable.ForeignKeys[0].RefTable = FilesTable PasskeysTable.ForeignKeys[0].RefTable = UsersTable SharesTable.ForeignKeys[0].RefTable = FilesTable SharesTable.ForeignKeys[1].RefTable = UsersTable StoragePoliciesTable.ForeignKeys[0].RefTable = NodesTable TasksTable.ForeignKeys[0].RefTable = UsersTable - UsersTable.ForeignKeys[0].RefTable = GroupsTable FileEntitiesTable.ForeignKeys[0].RefTable = FilesTable FileEntitiesTable.ForeignKeys[1].RefTable = EntitiesTable } diff --git a/ent/mutation.go b/ent/mutation.go index 5a612a26..643af055 100644 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -16,6 +16,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/file" "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/membership" "github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/passkey" @@ -45,6 +46,7 @@ const ( TypeEntity = "Entity" TypeFile = "File" TypeGroup = "Group" + TypeMembership = "Membership" TypeMetadata = "Metadata" TypeNode = "Node" TypePasskey = "Passkey" @@ -5680,6 +5682,480 @@ func (m *GroupMutation) ResetEdge(name string) error { return fmt.Errorf("unknown Group edge %s", name) } +// MembershipMutation represents an operation that mutates the Membership nodes in the graph. +type MembershipMutation struct { + config + op Op + typ string + created_at *time.Time + expires_at *time.Time + clearedFields map[string]struct{} + user *int + cleareduser bool + group *int + clearedgroup bool + done bool + oldValue func(context.Context) (*Membership, error) + predicates []predicate.Membership +} + +var _ ent.Mutation = (*MembershipMutation)(nil) + +// membershipOption allows management of the mutation configuration using functional options. +type membershipOption func(*MembershipMutation) + +// newMembershipMutation creates new mutation for the Membership entity. +func newMembershipMutation(c config, op Op, opts ...membershipOption) *MembershipMutation { + m := &MembershipMutation{ + config: c, + op: op, + typ: TypeMembership, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m MembershipMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m MembershipMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// SetUserID sets the "user_id" field. +func (m *MembershipMutation) SetUserID(i int) { + m.user = &i +} + +// UserID returns the value of the "user_id" field in the mutation. +func (m *MembershipMutation) UserID() (r int, exists bool) { + v := m.user + if v == nil { + return + } + return *v, true +} + +// ResetUserID resets all changes to the "user_id" field. +func (m *MembershipMutation) ResetUserID() { + m.user = nil +} + +// SetGroupID sets the "group_id" field. +func (m *MembershipMutation) SetGroupID(i int) { + m.group = &i +} + +// GroupID returns the value of the "group_id" field in the mutation. +func (m *MembershipMutation) GroupID() (r int, exists bool) { + v := m.group + if v == nil { + return + } + return *v, true +} + +// ResetGroupID resets all changes to the "group_id" field. +func (m *MembershipMutation) ResetGroupID() { + m.group = nil +} + +// SetCreatedAt sets the "created_at" field. +func (m *MembershipMutation) SetCreatedAt(t time.Time) { + m.created_at = &t +} + +// CreatedAt returns the value of the "created_at" field in the mutation. +func (m *MembershipMutation) CreatedAt() (r time.Time, exists bool) { + v := m.created_at + if v == nil { + return + } + return *v, true +} + +// ResetCreatedAt resets all changes to the "created_at" field. +func (m *MembershipMutation) ResetCreatedAt() { + m.created_at = nil +} + +// SetExpiresAt sets the "expires_at" field. +func (m *MembershipMutation) SetExpiresAt(t time.Time) { + m.expires_at = &t +} + +// ExpiresAt returns the value of the "expires_at" field in the mutation. +func (m *MembershipMutation) ExpiresAt() (r time.Time, exists bool) { + v := m.expires_at + if v == nil { + return + } + return *v, true +} + +// ClearExpiresAt clears the value of the "expires_at" field. +func (m *MembershipMutation) ClearExpiresAt() { + m.expires_at = nil + m.clearedFields[membership.FieldExpiresAt] = struct{}{} +} + +// ExpiresAtCleared returns if the "expires_at" field was cleared in this mutation. +func (m *MembershipMutation) ExpiresAtCleared() bool { + _, ok := m.clearedFields[membership.FieldExpiresAt] + return ok +} + +// ResetExpiresAt resets all changes to the "expires_at" field. +func (m *MembershipMutation) ResetExpiresAt() { + m.expires_at = nil + delete(m.clearedFields, membership.FieldExpiresAt) +} + +// ClearUser clears the "user" edge to the User entity. +func (m *MembershipMutation) ClearUser() { + m.cleareduser = true + m.clearedFields[membership.FieldUserID] = struct{}{} +} + +// UserCleared reports if the "user" edge to the User entity was cleared. +func (m *MembershipMutation) UserCleared() bool { + return m.cleareduser +} + +// UserIDs returns the "user" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// UserID instead. It exists only for internal usage by the builders. +func (m *MembershipMutation) UserIDs() (ids []int) { + if id := m.user; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetUser resets all changes to the "user" edge. +func (m *MembershipMutation) ResetUser() { + m.user = nil + m.cleareduser = false +} + +// ClearGroup clears the "group" edge to the Group entity. +func (m *MembershipMutation) ClearGroup() { + m.clearedgroup = true + m.clearedFields[membership.FieldGroupID] = struct{}{} +} + +// GroupCleared reports if the "group" edge to the Group entity was cleared. +func (m *MembershipMutation) GroupCleared() bool { + return m.clearedgroup +} + +// GroupIDs returns the "group" edge IDs in the mutation. +// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use +// GroupID instead. It exists only for internal usage by the builders. +func (m *MembershipMutation) GroupIDs() (ids []int) { + if id := m.group; id != nil { + ids = append(ids, *id) + } + return +} + +// ResetGroup resets all changes to the "group" edge. +func (m *MembershipMutation) ResetGroup() { + m.group = nil + m.clearedgroup = false +} + +// Where appends a list predicates to the MembershipMutation builder. +func (m *MembershipMutation) Where(ps ...predicate.Membership) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the MembershipMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *MembershipMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.Membership, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *MembershipMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *MembershipMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (Membership). +func (m *MembershipMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *MembershipMutation) Fields() []string { + fields := make([]string, 0, 4) + if m.user != nil { + fields = append(fields, membership.FieldUserID) + } + if m.group != nil { + fields = append(fields, membership.FieldGroupID) + } + if m.created_at != nil { + fields = append(fields, membership.FieldCreatedAt) + } + if m.expires_at != nil { + fields = append(fields, membership.FieldExpiresAt) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *MembershipMutation) Field(name string) (ent.Value, bool) { + switch name { + case membership.FieldUserID: + return m.UserID() + case membership.FieldGroupID: + return m.GroupID() + case membership.FieldCreatedAt: + return m.CreatedAt() + case membership.FieldExpiresAt: + return m.ExpiresAt() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *MembershipMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + return nil, errors.New("edge schema Membership does not support getting old values") +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *MembershipMutation) SetField(name string, value ent.Value) error { + switch name { + case membership.FieldUserID: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUserID(v) + return nil + case membership.FieldGroupID: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetGroupID(v) + return nil + case membership.FieldCreatedAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreatedAt(v) + return nil + case membership.FieldExpiresAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetExpiresAt(v) + return nil + } + return fmt.Errorf("unknown Membership field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *MembershipMutation) AddedFields() []string { + var fields []string + return fields +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *MembershipMutation) AddedField(name string) (ent.Value, bool) { + switch name { + } + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *MembershipMutation) AddField(name string, value ent.Value) error { + switch name { + } + return fmt.Errorf("unknown Membership numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *MembershipMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(membership.FieldExpiresAt) { + fields = append(fields, membership.FieldExpiresAt) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *MembershipMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *MembershipMutation) ClearField(name string) error { + switch name { + case membership.FieldExpiresAt: + m.ClearExpiresAt() + return nil + } + return fmt.Errorf("unknown Membership nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *MembershipMutation) ResetField(name string) error { + switch name { + case membership.FieldUserID: + m.ResetUserID() + return nil + case membership.FieldGroupID: + m.ResetGroupID() + return nil + case membership.FieldCreatedAt: + m.ResetCreatedAt() + return nil + case membership.FieldExpiresAt: + m.ResetExpiresAt() + return nil + } + return fmt.Errorf("unknown Membership field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *MembershipMutation) AddedEdges() []string { + edges := make([]string, 0, 2) + if m.user != nil { + edges = append(edges, membership.EdgeUser) + } + if m.group != nil { + edges = append(edges, membership.EdgeGroup) + } + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *MembershipMutation) AddedIDs(name string) []ent.Value { + switch name { + case membership.EdgeUser: + if id := m.user; id != nil { + return []ent.Value{*id} + } + case membership.EdgeGroup: + if id := m.group; id != nil { + return []ent.Value{*id} + } + } + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *MembershipMutation) RemovedEdges() []string { + edges := make([]string, 0, 2) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *MembershipMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *MembershipMutation) ClearedEdges() []string { + edges := make([]string, 0, 2) + if m.cleareduser { + edges = append(edges, membership.EdgeUser) + } + if m.clearedgroup { + edges = append(edges, membership.EdgeGroup) + } + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *MembershipMutation) EdgeCleared(name string) bool { + switch name { + case membership.EdgeUser: + return m.cleareduser + case membership.EdgeGroup: + return m.clearedgroup + } + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *MembershipMutation) ClearEdge(name string) error { + switch name { + case membership.EdgeUser: + m.ClearUser() + return nil + case membership.EdgeGroup: + m.ClearGroup() + return nil + } + return fmt.Errorf("unknown Membership unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *MembershipMutation) ResetEdge(name string) error { + switch name { + case membership.EdgeUser: + m.ResetUser() + return nil + case membership.EdgeGroup: + m.ResetGroup() + return nil + } + return fmt.Errorf("unknown Membership edge %s", name) +} + // MetadataMutation represents an operation that mutates the Metadata nodes in the graph. type MetadataMutation struct { config @@ -12515,7 +12991,8 @@ type UserMutation struct { avatar *string settings **types.UserSetting clearedFields map[string]struct{} - group *int + group map[int]struct{} + removedgroup map[int]struct{} clearedgroup bool files map[int]struct{} removedfiles map[int]struct{} @@ -13119,51 +13596,19 @@ func (m *UserMutation) ResetSettings() { delete(m.clearedFields, user.FieldSettings) } -// SetGroupUsers sets the "group_users" field. -func (m *UserMutation) SetGroupUsers(i int) { - m.group = &i -} - -// GroupUsers returns the value of the "group_users" field in the mutation. -func (m *UserMutation) GroupUsers() (r int, exists bool) { - v := m.group - if v == nil { - return - } - return *v, true -} - -// OldGroupUsers returns the old "group_users" field's value of the User entity. -// If the User object wasn't provided to the builder, the object is fetched from the database. -// An error is returned if the mutation operation is not UpdateOne, or the database query fails. -func (m *UserMutation) OldGroupUsers(ctx context.Context) (v int, err error) { - if !m.op.Is(OpUpdateOne) { - return v, errors.New("OldGroupUsers is only allowed on UpdateOne operations") +// AddGroupIDs adds the "group" edge to the Group entity by ids. +func (m *UserMutation) AddGroupIDs(ids ...int) { + if m.group == nil { + m.group = make(map[int]struct{}) } - if m.id == nil || m.oldValue == nil { - return v, errors.New("OldGroupUsers requires an ID field in the mutation") - } - oldValue, err := m.oldValue(ctx) - if err != nil { - return v, fmt.Errorf("querying old value for OldGroupUsers: %w", err) + for i := range ids { + m.group[ids[i]] = struct{}{} } - return oldValue.GroupUsers, nil -} - -// ResetGroupUsers resets all changes to the "group_users" field. -func (m *UserMutation) ResetGroupUsers() { - m.group = nil -} - -// SetGroupID sets the "group" edge to the Group entity by id. -func (m *UserMutation) SetGroupID(id int) { - m.group = &id } // ClearGroup clears the "group" edge to the Group entity. func (m *UserMutation) ClearGroup() { m.clearedgroup = true - m.clearedFields[user.FieldGroupUsers] = struct{}{} } // GroupCleared reports if the "group" edge to the Group entity was cleared. @@ -13171,20 +13616,29 @@ func (m *UserMutation) GroupCleared() bool { return m.clearedgroup } -// GroupID returns the "group" edge ID in the mutation. -func (m *UserMutation) GroupID() (id int, exists bool) { - if m.group != nil { - return *m.group, true +// RemoveGroupIDs removes the "group" edge to the Group entity by IDs. +func (m *UserMutation) RemoveGroupIDs(ids ...int) { + if m.removedgroup == nil { + m.removedgroup = make(map[int]struct{}) + } + for i := range ids { + delete(m.group, ids[i]) + m.removedgroup[ids[i]] = struct{}{} + } +} + +// RemovedGroup returns the removed IDs of the "group" edge to the Group entity. +func (m *UserMutation) RemovedGroupIDs() (ids []int) { + for id := range m.removedgroup { + ids = append(ids, id) } return } // GroupIDs returns the "group" edge IDs in the mutation. -// Note that IDs always returns len(IDs) <= 1 for unique edges, and you should use -// GroupID instead. It exists only for internal usage by the builders. func (m *UserMutation) GroupIDs() (ids []int) { - if id := m.group; id != nil { - ids = append(ids, *id) + for id := range m.group { + ids = append(ids, id) } return } @@ -13193,6 +13647,7 @@ func (m *UserMutation) GroupIDs() (ids []int) { func (m *UserMutation) ResetGroup() { m.group = nil m.clearedgroup = false + m.removedgroup = nil } // AddFileIDs adds the "files" edge to the File entity by ids. @@ -13553,7 +14008,7 @@ func (m *UserMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *UserMutation) Fields() []string { - fields := make([]string, 0, 12) + fields := make([]string, 0, 11) if m.created_at != nil { fields = append(fields, user.FieldCreatedAt) } @@ -13587,9 +14042,6 @@ func (m *UserMutation) Fields() []string { if m.settings != nil { fields = append(fields, user.FieldSettings) } - if m.group != nil { - fields = append(fields, user.FieldGroupUsers) - } return fields } @@ -13620,8 +14072,6 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) { return m.Avatar() case user.FieldSettings: return m.Settings() - case user.FieldGroupUsers: - return m.GroupUsers() } return nil, false } @@ -13653,8 +14103,6 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er return m.OldAvatar(ctx) case user.FieldSettings: return m.OldSettings(ctx) - case user.FieldGroupUsers: - return m.OldGroupUsers(ctx) } return nil, fmt.Errorf("unknown User field %s", name) } @@ -13741,13 +14189,6 @@ func (m *UserMutation) SetField(name string, value ent.Value) error { } m.SetSettings(v) return nil - case user.FieldGroupUsers: - v, ok := value.(int) - if !ok { - return fmt.Errorf("unexpected type %T for field %s", value, name) - } - m.SetGroupUsers(v) - return nil } return fmt.Errorf("unknown User field %s", name) } @@ -13878,9 +14319,6 @@ func (m *UserMutation) ResetField(name string) error { case user.FieldSettings: m.ResetSettings() return nil - case user.FieldGroupUsers: - m.ResetGroupUsers() - return nil } return fmt.Errorf("unknown User field %s", name) } @@ -13917,9 +14355,11 @@ func (m *UserMutation) AddedEdges() []string { func (m *UserMutation) AddedIDs(name string) []ent.Value { switch name { case user.EdgeGroup: - if id := m.group; id != nil { - return []ent.Value{*id} + ids := make([]ent.Value, 0, len(m.group)) + for id := range m.group { + ids = append(ids, id) } + return ids case user.EdgeFiles: ids := make([]ent.Value, 0, len(m.files)) for id := range m.files { @@ -13963,6 +14403,9 @@ func (m *UserMutation) AddedIDs(name string) []ent.Value { // RemovedEdges returns all edge names that were removed in this mutation. func (m *UserMutation) RemovedEdges() []string { edges := make([]string, 0, 7) + if m.removedgroup != nil { + edges = append(edges, user.EdgeGroup) + } if m.removedfiles != nil { edges = append(edges, user.EdgeFiles) } @@ -13988,6 +14431,12 @@ func (m *UserMutation) RemovedEdges() []string { // the given name in this mutation. func (m *UserMutation) RemovedIDs(name string) []ent.Value { switch name { + case user.EdgeGroup: + ids := make([]ent.Value, 0, len(m.removedgroup)) + for id := range m.removedgroup { + ids = append(ids, id) + } + return ids case user.EdgeFiles: ids := make([]ent.Value, 0, len(m.removedfiles)) for id := range m.removedfiles { @@ -14081,9 +14530,6 @@ func (m *UserMutation) EdgeCleared(name string) bool { // if that edge is not defined in the schema. func (m *UserMutation) ClearEdge(name string) error { switch name { - case user.EdgeGroup: - m.ClearGroup() - return nil } return fmt.Errorf("unknown User unique edge %s", name) } diff --git a/ent/mutationhelper.go b/ent/mutationhelper.go index 86d1931f..9af909e6 100644 --- a/ent/mutationhelper.go +++ b/ent/mutationhelper.go @@ -34,6 +34,8 @@ func (m *GroupMutation) SetRawID(t int) { // SetUpdatedAt sets the "updated_at" field. +// SetUpdatedAt sets the "updated_at" field. + func (m *MetadataMutation) SetRawID(t int) { m.id = &t } diff --git a/ent/predicate/predicate.go b/ent/predicate/predicate.go index 3ee71805..3597264d 100644 --- a/ent/predicate/predicate.go +++ b/ent/predicate/predicate.go @@ -21,6 +21,9 @@ type File func(*sql.Selector) // Group is the predicate function for group builders. type Group func(*sql.Selector) +// Membership is the predicate function for membership builders. +type Membership func(*sql.Selector) + // Metadata is the predicate function for metadata builders. type Metadata func(*sql.Selector) diff --git a/ent/runtime/runtime.go b/ent/runtime/runtime.go index 90100484..fe30dcab 100644 --- a/ent/runtime/runtime.go +++ b/ent/runtime/runtime.go @@ -10,6 +10,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/file" "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/membership" "github.com/cloudreve/Cloudreve/v4/ent/metadata" "github.com/cloudreve/Cloudreve/v4/ent/node" "github.com/cloudreve/Cloudreve/v4/ent/passkey" @@ -130,6 +131,12 @@ func init() { groupDescSettings := groupFields[4].Descriptor() // group.DefaultSettings holds the default value on creation for the settings field. group.DefaultSettings = groupDescSettings.Default.(*types.GroupSetting) + membershipFields := schema.Membership{}.Fields() + _ = membershipFields + // membershipDescCreatedAt is the schema descriptor for created_at field. + membershipDescCreatedAt := membershipFields[2].Descriptor() + // membership.DefaultCreatedAt holds the default value on creation for the created_at field. + membership.DefaultCreatedAt = membershipDescCreatedAt.Default.(func() time.Time) metadataMixin := schema.Metadata{}.Mixin() metadataMixinHooks0 := metadataMixin[0].Hooks() metadata.Hooks[0] = metadataMixinHooks0[0] diff --git a/ent/schema/group.go b/ent/schema/group.go index ca1613b8..9a6b10e8 100644 --- a/ent/schema/group.go +++ b/ent/schema/group.go @@ -36,7 +36,7 @@ func (Group) Mixin() []ent.Mixin { func (Group) Edges() []ent.Edge { return []ent.Edge{ - edge.To("users", User.Type), + edge.To("users", User.Type).Through("membership", Membership.Type), edge.From("storage_policies", StoragePolicy.Type). Ref("groups"). Field("storage_policy_id"). diff --git a/ent/schema/membership.go b/ent/schema/membership.go new file mode 100644 index 00000000..ffda7532 --- /dev/null +++ b/ent/schema/membership.go @@ -0,0 +1,43 @@ +package schema + +import ( + "time" + + "entgo.io/ent" + "entgo.io/ent/schema" + "entgo.io/ent/schema/edge" + "entgo.io/ent/schema/field" +) + +// Membership holds the schema definition for the Membership entity. +type Membership struct { + ent.Schema +} + +func (Membership) Annotations() []schema.Annotation { + return []schema.Annotation{ + field.ID("group_id", "user_id"), + } +} + +func (Membership) Fields() []ent.Field { + return []ent.Field{ + field.Int("user_id"), + field.Int("group_id"), + field.Time("created_at").Default(time.Now), + field.Time("expires_at").Nillable().Optional(), + } +} + +func (Membership) Edges() []ent.Edge { + return []ent.Edge{ + edge.To("user", User.Type). + Unique(). + Required(). + Field("user_id"), + edge.To("group", Group.Type). + Unique(). + Required(). + Field("group_id"), + } +} diff --git a/ent/schema/user.go b/ent/schema/user.go index 23cba9c7..0062e1c6 100644 --- a/ent/schema/user.go +++ b/ent/schema/user.go @@ -35,7 +35,6 @@ func (User) Fields() []ent.Field { field.JSON("settings", &types.UserSetting{}). Default(&types.UserSetting{}). Optional(), - field.Int("group_users"), } } @@ -43,9 +42,7 @@ func (User) Edges() []ent.Edge { return []ent.Edge{ edge.From("group", Group.Type). Ref("users"). - Field("group_users"). - Unique(). - Required(), + Through("membership", Membership.Type), edge.To("files", File.Type), edge.To("dav_accounts", DavAccount.Type), edge.To("shares", Share.Type), diff --git a/ent/tx.go b/ent/tx.go index 98f9b540..d7b9d62b 100644 --- a/ent/tx.go +++ b/ent/tx.go @@ -24,6 +24,8 @@ type Tx struct { File *FileClient // Group is the client for interacting with the Group builders. Group *GroupClient + // Membership is the client for interacting with the Membership builders. + Membership *MembershipClient // Metadata is the client for interacting with the Metadata builders. Metadata *MetadataClient // Node is the client for interacting with the Node builders. @@ -176,6 +178,7 @@ func (tx *Tx) init() { tx.Entity = NewEntityClient(tx.config) tx.File = NewFileClient(tx.config) tx.Group = NewGroupClient(tx.config) + tx.Membership = NewMembershipClient(tx.config) tx.Metadata = NewMetadataClient(tx.config) tx.Node = NewNodeClient(tx.config) tx.Passkey = NewPasskeyClient(tx.config) diff --git a/ent/user.go b/ent/user.go index 8b361f64..9546590b 100644 --- a/ent/user.go +++ b/ent/user.go @@ -10,7 +10,6 @@ import ( "entgo.io/ent" "entgo.io/ent/dialect/sql" - "github.com/cloudreve/Cloudreve/v4/ent/group" "github.com/cloudreve/Cloudreve/v4/ent/user" "github.com/cloudreve/Cloudreve/v4/inventory/types" ) @@ -42,8 +41,6 @@ type User struct { Avatar string `json:"avatar,omitempty"` // Settings holds the value of the "settings" field. Settings *types.UserSetting `json:"settings,omitempty"` - // GroupUsers holds the value of the "group_users" field. - GroupUsers int `json:"group_users,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the UserQuery when eager-loading is set. Edges UserEdges `json:"edges"` @@ -53,7 +50,7 @@ type User struct { // UserEdges holds the relations/edges for other nodes in the graph. type UserEdges struct { // Group holds the value of the group edge. - Group *Group `json:"group,omitempty"` + Group []*Group `json:"group,omitempty"` // Files holds the value of the files edge. Files []*File `json:"files,omitempty"` // DavAccounts holds the value of the dav_accounts edge. @@ -66,19 +63,17 @@ type UserEdges struct { Tasks []*Task `json:"tasks,omitempty"` // Entities holds the value of the entities edge. Entities []*Entity `json:"entities,omitempty"` + // Membership holds the value of the membership edge. + Membership []*Membership `json:"membership,omitempty"` // loadedTypes holds the information for reporting if a // type was loaded (or requested) in eager-loading or not. - loadedTypes [7]bool + loadedTypes [8]bool } // GroupOrErr returns the Group value or an error if the edge -// was not loaded in eager-loading, or loaded but was not found. -func (e UserEdges) GroupOrErr() (*Group, error) { +// was not loaded in eager-loading. +func (e UserEdges) GroupOrErr() ([]*Group, error) { if e.loadedTypes[0] { - if e.Group == nil { - // Edge was loaded but was not found. - return nil, &NotFoundError{label: group.Label} - } return e.Group, nil } return nil, &NotLoadedError{edge: "group"} @@ -138,6 +133,15 @@ func (e UserEdges) EntitiesOrErr() ([]*Entity, error) { return nil, &NotLoadedError{edge: "entities"} } +// MembershipOrErr returns the Membership value or an error if the edge +// was not loaded in eager-loading. +func (e UserEdges) MembershipOrErr() ([]*Membership, error) { + if e.loadedTypes[7] { + return e.Membership, nil + } + return nil, &NotLoadedError{edge: "membership"} +} + // scanValues returns the types for scanning values from sql.Rows. func (*User) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) @@ -145,7 +149,7 @@ func (*User) scanValues(columns []string) ([]any, error) { switch columns[i] { case user.FieldSettings: values[i] = new([]byte) - case user.FieldID, user.FieldStorage, user.FieldGroupUsers: + case user.FieldID, user.FieldStorage: values[i] = new(sql.NullInt64) case user.FieldEmail, user.FieldNick, user.FieldPassword, user.FieldStatus, user.FieldTwoFactorSecret, user.FieldAvatar: values[i] = new(sql.NullString) @@ -241,12 +245,6 @@ func (u *User) assignValues(columns []string, values []any) error { return fmt.Errorf("unmarshal field settings: %w", err) } } - case user.FieldGroupUsers: - if value, ok := values[i].(*sql.NullInt64); !ok { - return fmt.Errorf("unexpected type %T for field group_users", values[i]) - } else if value.Valid { - u.GroupUsers = int(value.Int64) - } default: u.selectValues.Set(columns[i], values[i]) } @@ -295,6 +293,11 @@ func (u *User) QueryEntities() *EntityQuery { return NewUserClient(u.config).QueryEntities(u) } +// QueryMembership queries the "membership" edge of the User entity. +func (u *User) QueryMembership() *MembershipQuery { + return NewUserClient(u.config).QueryMembership(u) +} + // Update returns a builder for updating this User. // Note that you need to call User.Unwrap() before calling this method if this User // was returned from a transaction, and the transaction was committed or rolled back. @@ -350,15 +353,12 @@ func (u *User) String() string { builder.WriteString(", ") builder.WriteString("settings=") builder.WriteString(fmt.Sprintf("%v", u.Settings)) - builder.WriteString(", ") - builder.WriteString("group_users=") - builder.WriteString(fmt.Sprintf("%v", u.GroupUsers)) builder.WriteByte(')') return builder.String() } // SetGroup manually set the edge as loaded state. -func (e *User) SetGroup(v *Group) { +func (e *User) SetGroup(v []*Group) { e.Edges.Group = v e.Edges.loadedTypes[0] = true } @@ -399,5 +399,11 @@ func (e *User) SetEntities(v []*Entity) { e.Edges.loadedTypes[6] = true } +// SetMembership manually set the edge as loaded state. +func (e *User) SetMembership(v []*Membership) { + e.Edges.Membership = v + e.Edges.loadedTypes[7] = true +} + // Users is a parsable slice of User. type Users []*User diff --git a/ent/user/user.go b/ent/user/user.go index 8ff28fbf..3ba63ef0 100644 --- a/ent/user/user.go +++ b/ent/user/user.go @@ -39,8 +39,6 @@ const ( FieldAvatar = "avatar" // FieldSettings holds the string denoting the settings field in the database. FieldSettings = "settings" - // FieldGroupUsers holds the string denoting the group_users field in the database. - FieldGroupUsers = "group_users" // EdgeGroup holds the string denoting the group edge name in mutations. EdgeGroup = "group" // EdgeFiles holds the string denoting the files edge name in mutations. @@ -55,15 +53,15 @@ const ( EdgeTasks = "tasks" // EdgeEntities holds the string denoting the entities edge name in mutations. EdgeEntities = "entities" + // EdgeMembership holds the string denoting the membership edge name in mutations. + EdgeMembership = "membership" // Table holds the table name of the user in the database. Table = "users" - // GroupTable is the table that holds the group relation/edge. - GroupTable = "users" + // GroupTable is the table that holds the group relation/edge. The primary key declared below. + GroupTable = "memberships" // GroupInverseTable is the table name for the Group entity. // It exists in this package in order to avoid circular dependency with the "group" package. GroupInverseTable = "groups" - // GroupColumn is the table column denoting the group relation/edge. - GroupColumn = "group_users" // FilesTable is the table that holds the files relation/edge. FilesTable = "files" // FilesInverseTable is the table name for the File entity. @@ -106,6 +104,13 @@ const ( EntitiesInverseTable = "entities" // EntitiesColumn is the table column denoting the entities relation/edge. EntitiesColumn = "created_by" + // MembershipTable is the table that holds the membership relation/edge. + MembershipTable = "memberships" + // MembershipInverseTable is the table name for the Membership entity. + // It exists in this package in order to avoid circular dependency with the "membership" package. + MembershipInverseTable = "memberships" + // MembershipColumn is the table column denoting the membership relation/edge. + MembershipColumn = "user_id" ) // Columns holds all SQL columns for user fields. @@ -122,9 +127,14 @@ var Columns = []string{ FieldTwoFactorSecret, FieldAvatar, FieldSettings, - FieldGroupUsers, } +var ( + // GroupPrimaryKey and GroupColumn2 are the table columns denoting the + // primary key for the group relation (M2M). + GroupPrimaryKey = []string{"group_id", "user_id"} +) + // ValidColumn reports if the column name is valid (part of the table columns). func ValidColumn(column string) bool { for i := range Columns { @@ -245,15 +255,17 @@ func ByAvatar(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldAvatar, opts...).ToFunc() } -// ByGroupUsers orders the results by the group_users field. -func ByGroupUsers(opts ...sql.OrderTermOption) OrderOption { - return sql.OrderByField(FieldGroupUsers, opts...).ToFunc() +// ByGroupCount orders the results by group count. +func ByGroupCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newGroupStep(), opts...) + } } -// ByGroupField orders the results by group field. -func ByGroupField(field string, opts ...sql.OrderTermOption) OrderOption { +// ByGroup orders the results by group terms. +func ByGroup(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { return func(s *sql.Selector) { - sqlgraph.OrderByNeighborTerms(s, newGroupStep(), sql.OrderByField(field, opts...)) + sqlgraph.OrderByNeighborTerms(s, newGroupStep(), append([]sql.OrderTerm{term}, terms...)...) } } @@ -340,11 +352,25 @@ func ByEntities(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { sqlgraph.OrderByNeighborTerms(s, newEntitiesStep(), append([]sql.OrderTerm{term}, terms...)...) } } + +// ByMembershipCount orders the results by membership count. +func ByMembershipCount(opts ...sql.OrderTermOption) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborsCount(s, newMembershipStep(), opts...) + } +} + +// ByMembership orders the results by membership terms. +func ByMembership(term sql.OrderTerm, terms ...sql.OrderTerm) OrderOption { + return func(s *sql.Selector) { + sqlgraph.OrderByNeighborTerms(s, newMembershipStep(), append([]sql.OrderTerm{term}, terms...)...) + } +} func newGroupStep() *sqlgraph.Step { return sqlgraph.NewStep( sqlgraph.From(Table, FieldID), sqlgraph.To(GroupInverseTable, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), + sqlgraph.Edge(sqlgraph.M2M, true, GroupTable, GroupPrimaryKey...), ) } func newFilesStep() *sqlgraph.Step { @@ -389,3 +415,10 @@ func newEntitiesStep() *sqlgraph.Step { sqlgraph.Edge(sqlgraph.O2M, false, EntitiesTable, EntitiesColumn), ) } +func newMembershipStep() *sqlgraph.Step { + return sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.To(MembershipInverseTable, MembershipColumn), + sqlgraph.Edge(sqlgraph.O2M, true, MembershipTable, MembershipColumn), + ) +} diff --git a/ent/user/where.go b/ent/user/where.go index 5400662a..9e3dc600 100644 --- a/ent/user/where.go +++ b/ent/user/where.go @@ -100,11 +100,6 @@ func Avatar(v string) predicate.User { return predicate.User(sql.FieldEQ(FieldAvatar, v)) } -// GroupUsers applies equality check predicate on the "group_users" field. It's identical to GroupUsersEQ. -func GroupUsers(v int) predicate.User { - return predicate.User(sql.FieldEQ(FieldGroupUsers, v)) -} - // CreatedAtEQ applies the EQ predicate on the "created_at" field. func CreatedAtEQ(v time.Time) predicate.User { return predicate.User(sql.FieldEQ(FieldCreatedAt, v)) @@ -660,32 +655,12 @@ func SettingsNotNil() predicate.User { return predicate.User(sql.FieldNotNull(FieldSettings)) } -// GroupUsersEQ applies the EQ predicate on the "group_users" field. -func GroupUsersEQ(v int) predicate.User { - return predicate.User(sql.FieldEQ(FieldGroupUsers, v)) -} - -// GroupUsersNEQ applies the NEQ predicate on the "group_users" field. -func GroupUsersNEQ(v int) predicate.User { - return predicate.User(sql.FieldNEQ(FieldGroupUsers, v)) -} - -// GroupUsersIn applies the In predicate on the "group_users" field. -func GroupUsersIn(vs ...int) predicate.User { - return predicate.User(sql.FieldIn(FieldGroupUsers, vs...)) -} - -// GroupUsersNotIn applies the NotIn predicate on the "group_users" field. -func GroupUsersNotIn(vs ...int) predicate.User { - return predicate.User(sql.FieldNotIn(FieldGroupUsers, vs...)) -} - // HasGroup applies the HasEdge predicate on the "group" edge. func HasGroup() predicate.User { return predicate.User(func(s *sql.Selector) { step := sqlgraph.NewStep( sqlgraph.From(Table, FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, GroupTable, GroupColumn), + sqlgraph.Edge(sqlgraph.M2M, true, GroupTable, GroupPrimaryKey...), ) sqlgraph.HasNeighbors(s, step) }) @@ -841,6 +816,29 @@ func HasEntitiesWith(preds ...predicate.Entity) predicate.User { }) } +// HasMembership applies the HasEdge predicate on the "membership" edge. +func HasMembership() predicate.User { + return predicate.User(func(s *sql.Selector) { + step := sqlgraph.NewStep( + sqlgraph.From(Table, FieldID), + sqlgraph.Edge(sqlgraph.O2M, true, MembershipTable, MembershipColumn), + ) + sqlgraph.HasNeighbors(s, step) + }) +} + +// HasMembershipWith applies the HasEdge predicate on the "membership" edge with a given conditions (other predicates). +func HasMembershipWith(preds ...predicate.Membership) predicate.User { + return predicate.User(func(s *sql.Selector) { + step := newMembershipStep() + sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { + for _, p := range preds { + p(s) + } + }) + }) +} + // And groups predicates with the AND operator between them. func And(predicates ...predicate.User) predicate.User { return predicate.User(sql.AndPredicates(predicates...)) diff --git a/ent/user_create.go b/ent/user_create.go index 4e5f9278..1af9272a 100644 --- a/ent/user_create.go +++ b/ent/user_create.go @@ -160,21 +160,19 @@ func (uc *UserCreate) SetSettings(ts *types.UserSetting) *UserCreate { return uc } -// SetGroupUsers sets the "group_users" field. -func (uc *UserCreate) SetGroupUsers(i int) *UserCreate { - uc.mutation.SetGroupUsers(i) +// AddGroupIDs adds the "group" edge to the Group entity by IDs. +func (uc *UserCreate) AddGroupIDs(ids ...int) *UserCreate { + uc.mutation.AddGroupIDs(ids...) return uc } -// SetGroupID sets the "group" edge to the Group entity by ID. -func (uc *UserCreate) SetGroupID(id int) *UserCreate { - uc.mutation.SetGroupID(id) - return uc -} - -// SetGroup sets the "group" edge to the Group entity. -func (uc *UserCreate) SetGroup(g *Group) *UserCreate { - return uc.SetGroupID(g.ID) +// AddGroup adds the "group" edges to the Group entity. +func (uc *UserCreate) AddGroup(g ...*Group) *UserCreate { + ids := make([]int, len(g)) + for i := range g { + ids[i] = g[i].ID + } + return uc.AddGroupIDs(ids...) } // AddFileIDs adds the "files" edge to the File entity by IDs. @@ -368,12 +366,6 @@ func (uc *UserCreate) check() error { if _, ok := uc.mutation.Storage(); !ok { return &ValidationError{Name: "storage", err: errors.New(`ent: missing required field "User.storage"`)} } - if _, ok := uc.mutation.GroupUsers(); !ok { - return &ValidationError{Name: "group_users", err: errors.New(`ent: missing required field "User.group_users"`)} - } - if _, ok := uc.mutation.GroupID(); !ok { - return &ValidationError{Name: "group", err: errors.New(`ent: missing required edge "User.group"`)} - } return nil } @@ -454,10 +446,10 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { } if nodes := uc.mutation.GroupIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, + Rel: sqlgraph.M2M, Inverse: true, Table: user.GroupTable, - Columns: []string{user.GroupColumn}, + Columns: user.GroupPrimaryKey, Bidi: false, Target: &sqlgraph.EdgeTarget{ IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeInt), @@ -466,7 +458,10 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { for _, k := range nodes { edge.Target.Nodes = append(edge.Target.Nodes, k) } - _node.GroupUsers = nodes[0] + createE := &MembershipCreate{config: uc.config, mutation: newMembershipMutation(uc.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields _spec.Edges = append(_spec.Edges, edge) } if nodes := uc.mutation.FilesIDs(); len(nodes) > 0 { @@ -773,18 +768,6 @@ func (u *UserUpsert) ClearSettings() *UserUpsert { return u } -// SetGroupUsers sets the "group_users" field. -func (u *UserUpsert) SetGroupUsers(v int) *UserUpsert { - u.Set(user.FieldGroupUsers, v) - return u -} - -// UpdateGroupUsers sets the "group_users" field to the value that was provided on create. -func (u *UserUpsert) UpdateGroupUsers() *UserUpsert { - u.SetExcluded(user.FieldGroupUsers) - return u -} - // UpdateNewValues updates the mutable fields using the new values that were set on create. // Using this option is equivalent to using: // @@ -1012,20 +995,6 @@ func (u *UserUpsertOne) ClearSettings() *UserUpsertOne { }) } -// SetGroupUsers sets the "group_users" field. -func (u *UserUpsertOne) SetGroupUsers(v int) *UserUpsertOne { - return u.Update(func(s *UserUpsert) { - s.SetGroupUsers(v) - }) -} - -// UpdateGroupUsers sets the "group_users" field to the value that was provided on create. -func (u *UserUpsertOne) UpdateGroupUsers() *UserUpsertOne { - return u.Update(func(s *UserUpsert) { - s.UpdateGroupUsers() - }) -} - // Exec executes the query. func (u *UserUpsertOne) Exec(ctx context.Context) error { if len(u.create.conflict) == 0 { @@ -1424,20 +1393,6 @@ func (u *UserUpsertBulk) ClearSettings() *UserUpsertBulk { }) } -// SetGroupUsers sets the "group_users" field. -func (u *UserUpsertBulk) SetGroupUsers(v int) *UserUpsertBulk { - return u.Update(func(s *UserUpsert) { - s.SetGroupUsers(v) - }) -} - -// UpdateGroupUsers sets the "group_users" field to the value that was provided on create. -func (u *UserUpsertBulk) UpdateGroupUsers() *UserUpsertBulk { - return u.Update(func(s *UserUpsert) { - s.UpdateGroupUsers() - }) -} - // Exec executes the query. func (u *UserUpsertBulk) Exec(ctx context.Context) error { if u.create.err != nil { diff --git a/ent/user_query.go b/ent/user_query.go index bbe8eb11..4e3026eb 100644 --- a/ent/user_query.go +++ b/ent/user_query.go @@ -15,6 +15,7 @@ import ( "github.com/cloudreve/Cloudreve/v4/ent/entity" "github.com/cloudreve/Cloudreve/v4/ent/file" "github.com/cloudreve/Cloudreve/v4/ent/group" + "github.com/cloudreve/Cloudreve/v4/ent/membership" "github.com/cloudreve/Cloudreve/v4/ent/passkey" "github.com/cloudreve/Cloudreve/v4/ent/predicate" "github.com/cloudreve/Cloudreve/v4/ent/share" @@ -36,6 +37,7 @@ type UserQuery struct { withPasskey *PasskeyQuery withTasks *TaskQuery withEntities *EntityQuery + withMembership *MembershipQuery // intermediate query (i.e. traversal path). sql *sql.Selector path func(context.Context) (*sql.Selector, error) @@ -86,7 +88,7 @@ func (uq *UserQuery) QueryGroup() *GroupQuery { step := sqlgraph.NewStep( sqlgraph.From(user.Table, user.FieldID, selector), sqlgraph.To(group.Table, group.FieldID), - sqlgraph.Edge(sqlgraph.M2O, true, user.GroupTable, user.GroupColumn), + sqlgraph.Edge(sqlgraph.M2M, true, user.GroupTable, user.GroupPrimaryKey...), ) fromU = sqlgraph.SetNeighbors(uq.driver.Dialect(), step) return fromU, nil @@ -226,6 +228,28 @@ func (uq *UserQuery) QueryEntities() *EntityQuery { return query } +// QueryMembership chains the current query on the "membership" edge. +func (uq *UserQuery) QueryMembership() *MembershipQuery { + query := (&MembershipClient{config: uq.config}).Query() + query.path = func(ctx context.Context) (fromU *sql.Selector, err error) { + if err := uq.prepareQuery(ctx); err != nil { + return nil, err + } + selector := uq.sqlQuery(ctx) + if err := selector.Err(); err != nil { + return nil, err + } + step := sqlgraph.NewStep( + sqlgraph.From(user.Table, user.FieldID, selector), + sqlgraph.To(membership.Table, membership.UserColumn), + sqlgraph.Edge(sqlgraph.O2M, true, user.MembershipTable, user.MembershipColumn), + ) + fromU = sqlgraph.SetNeighbors(uq.driver.Dialect(), step) + return fromU, nil + } + return query +} + // First returns the first User entity from the query. // Returns a *NotFoundError when no User was found. func (uq *UserQuery) First(ctx context.Context) (*User, error) { @@ -425,6 +449,7 @@ func (uq *UserQuery) Clone() *UserQuery { withPasskey: uq.withPasskey.Clone(), withTasks: uq.withTasks.Clone(), withEntities: uq.withEntities.Clone(), + withMembership: uq.withMembership.Clone(), // clone intermediate query. sql: uq.sql.Clone(), path: uq.path, @@ -508,6 +533,17 @@ func (uq *UserQuery) WithEntities(opts ...func(*EntityQuery)) *UserQuery { return uq } +// WithMembership tells the query-builder to eager-load the nodes that are connected to +// the "membership" edge. The optional arguments are used to configure the query builder of the edge. +func (uq *UserQuery) WithMembership(opts ...func(*MembershipQuery)) *UserQuery { + query := (&MembershipClient{config: uq.config}).Query() + for _, opt := range opts { + opt(query) + } + uq.withMembership = query + return uq +} + // GroupBy is used to group vertices by one or more fields/columns. // It is often used with aggregate functions, like: count, max, mean, min, sum. // @@ -586,7 +622,7 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e var ( nodes = []*User{} _spec = uq.querySpec() - loadedTypes = [7]bool{ + loadedTypes = [8]bool{ uq.withGroup != nil, uq.withFiles != nil, uq.withDavAccounts != nil, @@ -594,6 +630,7 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e uq.withPasskey != nil, uq.withTasks != nil, uq.withEntities != nil, + uq.withMembership != nil, } ) _spec.ScanValues = func(columns []string) ([]any, error) { @@ -615,8 +652,9 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e return nodes, nil } if query := uq.withGroup; query != nil { - if err := uq.loadGroup(ctx, query, nodes, nil, - func(n *User, e *Group) { n.Edges.Group = e }); err != nil { + if err := uq.loadGroup(ctx, query, nodes, + func(n *User) { n.Edges.Group = []*Group{} }, + func(n *User, e *Group) { n.Edges.Group = append(n.Edges.Group, e) }); err != nil { return nil, err } } @@ -662,34 +700,73 @@ func (uq *UserQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*User, e return nil, err } } + if query := uq.withMembership; query != nil { + if err := uq.loadMembership(ctx, query, nodes, + func(n *User) { n.Edges.Membership = []*Membership{} }, + func(n *User, e *Membership) { n.Edges.Membership = append(n.Edges.Membership, e) }); err != nil { + return nil, err + } + } return nodes, nil } func (uq *UserQuery) loadGroup(ctx context.Context, query *GroupQuery, nodes []*User, init func(*User), assign func(*User, *Group)) error { - ids := make([]int, 0, len(nodes)) - nodeids := make(map[int][]*User) - for i := range nodes { - fk := nodes[i].GroupUsers - if _, ok := nodeids[fk]; !ok { - ids = append(ids, fk) + edgeIDs := make([]driver.Value, len(nodes)) + byID := make(map[int]*User) + nids := make(map[int]map[*User]struct{}) + for i, node := range nodes { + edgeIDs[i] = node.ID + byID[node.ID] = node + if init != nil { + init(node) } - nodeids[fk] = append(nodeids[fk], nodes[i]) } - if len(ids) == 0 { - return nil + query.Where(func(s *sql.Selector) { + joinT := sql.Table(user.GroupTable) + s.Join(joinT).On(s.C(group.FieldID), joinT.C(user.GroupPrimaryKey[0])) + s.Where(sql.InValues(joinT.C(user.GroupPrimaryKey[1]), edgeIDs...)) + columns := s.SelectedColumns() + s.Select(joinT.C(user.GroupPrimaryKey[1])) + s.AppendSelect(columns...) + s.SetDistinct(false) + }) + if err := query.prepareQuery(ctx); err != nil { + return err } - query.Where(group.IDIn(ids...)) - neighbors, err := query.All(ctx) + qr := QuerierFunc(func(ctx context.Context, q Query) (Value, error) { + return query.sqlAll(ctx, func(_ context.Context, spec *sqlgraph.QuerySpec) { + assign := spec.Assign + values := spec.ScanValues + spec.ScanValues = func(columns []string) ([]any, error) { + values, err := values(columns[1:]) + if err != nil { + return nil, err + } + return append([]any{new(sql.NullInt64)}, values...), nil + } + spec.Assign = func(columns []string, values []any) error { + outValue := int(values[0].(*sql.NullInt64).Int64) + inValue := int(values[1].(*sql.NullInt64).Int64) + if nids[inValue] == nil { + nids[inValue] = map[*User]struct{}{byID[outValue]: {}} + return assign(columns[1:], values[1:]) + } + nids[inValue][byID[outValue]] = struct{}{} + return nil + } + }) + }) + neighbors, err := withInterceptors[[]*Group](ctx, query, qr, query.inters) if err != nil { return err } for _, n := range neighbors { - nodes, ok := nodeids[n.ID] + nodes, ok := nids[n.ID] if !ok { - return fmt.Errorf(`unexpected foreign-key "group_users" returned %v`, n.ID) + return fmt.Errorf(`unexpected "group" node returned %v`, n.ID) } - for i := range nodes { - assign(nodes[i], n) + for kn := range nodes { + assign(kn, n) } } return nil @@ -875,6 +952,36 @@ func (uq *UserQuery) loadEntities(ctx context.Context, query *EntityQuery, nodes } return nil } +func (uq *UserQuery) loadMembership(ctx context.Context, query *MembershipQuery, nodes []*User, init func(*User), assign func(*User, *Membership)) error { + fks := make([]driver.Value, 0, len(nodes)) + nodeids := make(map[int]*User) + for i := range nodes { + fks = append(fks, nodes[i].ID) + nodeids[nodes[i].ID] = nodes[i] + if init != nil { + init(nodes[i]) + } + } + if len(query.ctx.Fields) > 0 { + query.ctx.AppendFieldOnce(membership.FieldUserID) + } + query.Where(predicate.Membership(func(s *sql.Selector) { + s.Where(sql.InValues(s.C(user.MembershipColumn), fks...)) + })) + neighbors, err := query.All(ctx) + if err != nil { + return err + } + for _, n := range neighbors { + fk := n.UserID + node, ok := nodeids[fk] + if !ok { + return fmt.Errorf(`unexpected referenced foreign-key "user_id" returned %v for node %v`, fk, n) + } + assign(node, n) + } + return nil +} func (uq *UserQuery) sqlCount(ctx context.Context) (int, error) { _spec := uq.querySpec() @@ -901,9 +1008,6 @@ func (uq *UserQuery) querySpec() *sqlgraph.QuerySpec { _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) } } - if uq.withGroup != nil { - _spec.Node.AddColumnOnce(user.FieldGroupUsers) - } } if ps := uq.predicates; len(ps) > 0 { _spec.Predicate = func(selector *sql.Selector) { diff --git a/ent/user_update.go b/ent/user_update.go index 4d67894a..a69cccf7 100644 --- a/ent/user_update.go +++ b/ent/user_update.go @@ -197,29 +197,19 @@ func (uu *UserUpdate) ClearSettings() *UserUpdate { return uu } -// SetGroupUsers sets the "group_users" field. -func (uu *UserUpdate) SetGroupUsers(i int) *UserUpdate { - uu.mutation.SetGroupUsers(i) +// AddGroupIDs adds the "group" edge to the Group entity by IDs. +func (uu *UserUpdate) AddGroupIDs(ids ...int) *UserUpdate { + uu.mutation.AddGroupIDs(ids...) return uu } -// SetNillableGroupUsers sets the "group_users" field if the given value is not nil. -func (uu *UserUpdate) SetNillableGroupUsers(i *int) *UserUpdate { - if i != nil { - uu.SetGroupUsers(*i) +// AddGroup adds the "group" edges to the Group entity. +func (uu *UserUpdate) AddGroup(g ...*Group) *UserUpdate { + ids := make([]int, len(g)) + for i := range g { + ids[i] = g[i].ID } - return uu -} - -// SetGroupID sets the "group" edge to the Group entity by ID. -func (uu *UserUpdate) SetGroupID(id int) *UserUpdate { - uu.mutation.SetGroupID(id) - return uu -} - -// SetGroup sets the "group" edge to the Group entity. -func (uu *UserUpdate) SetGroup(g *Group) *UserUpdate { - return uu.SetGroupID(g.ID) + return uu.AddGroupIDs(ids...) } // AddFileIDs adds the "files" edge to the File entity by IDs. @@ -317,12 +307,27 @@ func (uu *UserUpdate) Mutation() *UserMutation { return uu.mutation } -// ClearGroup clears the "group" edge to the Group entity. +// ClearGroup clears all "group" edges to the Group entity. func (uu *UserUpdate) ClearGroup() *UserUpdate { uu.mutation.ClearGroup() return uu } +// RemoveGroupIDs removes the "group" edge to Group entities by IDs. +func (uu *UserUpdate) RemoveGroupIDs(ids ...int) *UserUpdate { + uu.mutation.RemoveGroupIDs(ids...) + return uu +} + +// RemoveGroup removes "group" edges to Group entities. +func (uu *UserUpdate) RemoveGroup(g ...*Group) *UserUpdate { + ids := make([]int, len(g)) + for i := range g { + ids[i] = g[i].ID + } + return uu.RemoveGroupIDs(ids...) +} + // ClearFiles clears all "files" edges to the File entity. func (uu *UserUpdate) ClearFiles() *UserUpdate { uu.mutation.ClearFiles() @@ -508,9 +513,6 @@ func (uu *UserUpdate) check() error { return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "User.status": %w`, err)} } } - if _, ok := uu.mutation.GroupID(); uu.mutation.GroupCleared() && !ok { - return errors.New(`ent: clearing a required unique edge "User.group"`) - } return nil } @@ -576,23 +578,47 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) { } if uu.mutation.GroupCleared() { edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, + Rel: sqlgraph.M2M, Inverse: true, Table: user.GroupTable, - Columns: []string{user.GroupColumn}, + Columns: user.GroupPrimaryKey, Bidi: false, Target: &sqlgraph.EdgeTarget{ IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeInt), }, } + createE := &MembershipCreate{config: uu.config, mutation: newMembershipMutation(uu.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uu.mutation.RemovedGroupIDs(); len(nodes) > 0 && !uu.mutation.GroupCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2M, + Inverse: true, + Table: user.GroupTable, + Columns: user.GroupPrimaryKey, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + createE := &MembershipCreate{config: uu.config, mutation: newMembershipMutation(uu.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields _spec.Edges.Clear = append(_spec.Edges.Clear, edge) } if nodes := uu.mutation.GroupIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, + Rel: sqlgraph.M2M, Inverse: true, Table: user.GroupTable, - Columns: []string{user.GroupColumn}, + Columns: user.GroupPrimaryKey, Bidi: false, Target: &sqlgraph.EdgeTarget{ IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeInt), @@ -601,6 +627,10 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) { for _, k := range nodes { edge.Target.Nodes = append(edge.Target.Nodes, k) } + createE := &MembershipCreate{config: uu.config, mutation: newMembershipMutation(uu.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields _spec.Edges.Add = append(_spec.Edges.Add, edge) } if uu.mutation.FilesCleared() { @@ -1054,29 +1084,19 @@ func (uuo *UserUpdateOne) ClearSettings() *UserUpdateOne { return uuo } -// SetGroupUsers sets the "group_users" field. -func (uuo *UserUpdateOne) SetGroupUsers(i int) *UserUpdateOne { - uuo.mutation.SetGroupUsers(i) +// AddGroupIDs adds the "group" edge to the Group entity by IDs. +func (uuo *UserUpdateOne) AddGroupIDs(ids ...int) *UserUpdateOne { + uuo.mutation.AddGroupIDs(ids...) return uuo } -// SetNillableGroupUsers sets the "group_users" field if the given value is not nil. -func (uuo *UserUpdateOne) SetNillableGroupUsers(i *int) *UserUpdateOne { - if i != nil { - uuo.SetGroupUsers(*i) +// AddGroup adds the "group" edges to the Group entity. +func (uuo *UserUpdateOne) AddGroup(g ...*Group) *UserUpdateOne { + ids := make([]int, len(g)) + for i := range g { + ids[i] = g[i].ID } - return uuo -} - -// SetGroupID sets the "group" edge to the Group entity by ID. -func (uuo *UserUpdateOne) SetGroupID(id int) *UserUpdateOne { - uuo.mutation.SetGroupID(id) - return uuo -} - -// SetGroup sets the "group" edge to the Group entity. -func (uuo *UserUpdateOne) SetGroup(g *Group) *UserUpdateOne { - return uuo.SetGroupID(g.ID) + return uuo.AddGroupIDs(ids...) } // AddFileIDs adds the "files" edge to the File entity by IDs. @@ -1174,12 +1194,27 @@ func (uuo *UserUpdateOne) Mutation() *UserMutation { return uuo.mutation } -// ClearGroup clears the "group" edge to the Group entity. +// ClearGroup clears all "group" edges to the Group entity. func (uuo *UserUpdateOne) ClearGroup() *UserUpdateOne { uuo.mutation.ClearGroup() return uuo } +// RemoveGroupIDs removes the "group" edge to Group entities by IDs. +func (uuo *UserUpdateOne) RemoveGroupIDs(ids ...int) *UserUpdateOne { + uuo.mutation.RemoveGroupIDs(ids...) + return uuo +} + +// RemoveGroup removes "group" edges to Group entities. +func (uuo *UserUpdateOne) RemoveGroup(g ...*Group) *UserUpdateOne { + ids := make([]int, len(g)) + for i := range g { + ids[i] = g[i].ID + } + return uuo.RemoveGroupIDs(ids...) +} + // ClearFiles clears all "files" edges to the File entity. func (uuo *UserUpdateOne) ClearFiles() *UserUpdateOne { uuo.mutation.ClearFiles() @@ -1378,9 +1413,6 @@ func (uuo *UserUpdateOne) check() error { return &ValidationError{Name: "status", err: fmt.Errorf(`ent: validator failed for field "User.status": %w`, err)} } } - if _, ok := uuo.mutation.GroupID(); uuo.mutation.GroupCleared() && !ok { - return errors.New(`ent: clearing a required unique edge "User.group"`) - } return nil } @@ -1463,23 +1495,47 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) } if uuo.mutation.GroupCleared() { edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, + Rel: sqlgraph.M2M, Inverse: true, Table: user.GroupTable, - Columns: []string{user.GroupColumn}, + Columns: user.GroupPrimaryKey, Bidi: false, Target: &sqlgraph.EdgeTarget{ IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeInt), }, } + createE := &MembershipCreate{config: uuo.config, mutation: newMembershipMutation(uuo.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields + _spec.Edges.Clear = append(_spec.Edges.Clear, edge) + } + if nodes := uuo.mutation.RemovedGroupIDs(); len(nodes) > 0 && !uuo.mutation.GroupCleared() { + edge := &sqlgraph.EdgeSpec{ + Rel: sqlgraph.M2M, + Inverse: true, + Table: user.GroupTable, + Columns: user.GroupPrimaryKey, + Bidi: false, + Target: &sqlgraph.EdgeTarget{ + IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeInt), + }, + } + for _, k := range nodes { + edge.Target.Nodes = append(edge.Target.Nodes, k) + } + createE := &MembershipCreate{config: uuo.config, mutation: newMembershipMutation(uuo.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields _spec.Edges.Clear = append(_spec.Edges.Clear, edge) } if nodes := uuo.mutation.GroupIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ - Rel: sqlgraph.M2O, + Rel: sqlgraph.M2M, Inverse: true, Table: user.GroupTable, - Columns: []string{user.GroupColumn}, + Columns: user.GroupPrimaryKey, Bidi: false, Target: &sqlgraph.EdgeTarget{ IDSpec: sqlgraph.NewFieldSpec(group.FieldID, field.TypeInt), @@ -1488,6 +1544,10 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) for _, k := range nodes { edge.Target.Nodes = append(edge.Target.Nodes, k) } + createE := &MembershipCreate{config: uuo.config, mutation: newMembershipMutation(uuo.config, OpCreate)} + createE.defaults() + _, specE := createE.createSpec() + edge.Target.Fields = specE.Fields _spec.Edges.Add = append(_spec.Edges.Add, edge) } if uuo.mutation.FilesCleared() { diff --git a/go.mod b/go.mod index c1834d6f..e975e6f6 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/abslant/gzip v0.0.9 github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible github.com/aws/aws-sdk-go v1.31.5 + github.com/bodgit/sevenzip v1.6.0 github.com/cloudflare/cfssl v1.6.1 github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25 github.com/dsoprea/go-exif/v3 v3.0.1 @@ -70,7 +71,6 @@ require ( github.com/andybalholm/brotli v1.1.2-0.20250424173009-453214e765f3 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/bodgit/plumbing v1.3.0 // indirect - github.com/bodgit/sevenzip v1.6.0 // indirect github.com/bodgit/windows v1.0.1 // indirect github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect github.com/bytedance/sonic v1.11.6 // indirect