diff --git a/Dockerfile b/Dockerfile index 5a080af..e1b879c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,6 +12,9 @@ RUN go mod download # Build the Go app RUN go build . +# Generate orm +RUN go generate ./ent + # Expose port 8080 for incoming traffic EXPOSE 4002 diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index a235873..c19a641 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -12,6 +12,7 @@ var ( UsersColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, {Name: "name", Type: field.TypeString, Default: "John doe"}, + {Name: "role", Type: field.TypeEnum, Enums: []string{"admin", "user", "visitor"}}, } // UsersTable holds the schema information for the "users" table. UsersTable = &schema.Table{ diff --git a/ent/mutation.go b/ent/mutation.go index 70f3952..82896c2 100644 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -33,6 +33,7 @@ type UserMutation struct { typ string id *int name *string + role *user.Role clearedFields map[string]struct{} done bool oldValue func(context.Context) (*User, error) @@ -173,6 +174,42 @@ func (m *UserMutation) ResetName() { m.name = nil } +// SetRole sets the "role" field. +func (m *UserMutation) SetRole(u user.Role) { + m.role = &u +} + +// Role returns the value of the "role" field in the mutation. +func (m *UserMutation) Role() (r user.Role, exists bool) { + v := m.role + if v == nil { + return + } + return *v, true +} + +// OldRole returns the old "role" 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) OldRole(ctx context.Context) (v user.Role, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldRole is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldRole requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldRole: %w", err) + } + return oldValue.Role, nil +} + +// ResetRole resets all changes to the "role" field. +func (m *UserMutation) ResetRole() { + m.role = nil +} + // Where appends a list predicates to the UserMutation builder. func (m *UserMutation) Where(ps ...predicate.User) { m.predicates = append(m.predicates, ps...) @@ -207,10 +244,13 @@ 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, 1) + fields := make([]string, 0, 2) if m.name != nil { fields = append(fields, user.FieldName) } + if m.role != nil { + fields = append(fields, user.FieldRole) + } return fields } @@ -221,6 +261,8 @@ func (m *UserMutation) Field(name string) (ent.Value, bool) { switch name { case user.FieldName: return m.Name() + case user.FieldRole: + return m.Role() } return nil, false } @@ -232,6 +274,8 @@ func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, er switch name { case user.FieldName: return m.OldName(ctx) + case user.FieldRole: + return m.OldRole(ctx) } return nil, fmt.Errorf("unknown User field %s", name) } @@ -248,6 +292,13 @@ func (m *UserMutation) SetField(name string, value ent.Value) error { } m.SetName(v) return nil + case user.FieldRole: + v, ok := value.(user.Role) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetRole(v) + return nil } return fmt.Errorf("unknown User field %s", name) } @@ -300,6 +351,9 @@ func (m *UserMutation) ResetField(name string) error { case user.FieldName: m.ResetName() return nil + case user.FieldRole: + m.ResetRole() + return nil } return fmt.Errorf("unknown User field %s", name) } diff --git a/ent/schema/user.go b/ent/schema/user.go index 5fa85f7..8686136 100644 --- a/ent/schema/user.go +++ b/ent/schema/user.go @@ -15,6 +15,8 @@ func (User) Fields() []ent.Field { return []ent.Field{ field.String("name"). Default("John doe"), + field.Enum("role"). + Values("admin", "user", "visitor"), } } diff --git a/ent/user.go b/ent/user.go index 136f635..37aa033 100644 --- a/ent/user.go +++ b/ent/user.go @@ -17,7 +17,9 @@ type User struct { // ID of the ent. ID int `json:"id,omitempty"` // Name holds the value of the "name" field. - Name string `json:"name,omitempty"` + Name string `json:"name,omitempty"` + // Role holds the value of the "role" field. + Role user.Role `json:"role,omitempty"` selectValues sql.SelectValues } @@ -28,7 +30,7 @@ func (*User) scanValues(columns []string) ([]any, error) { switch columns[i] { case user.FieldID: values[i] = new(sql.NullInt64) - case user.FieldName: + case user.FieldName, user.FieldRole: values[i] = new(sql.NullString) default: values[i] = new(sql.UnknownType) @@ -57,6 +59,12 @@ func (u *User) assignValues(columns []string, values []any) error { } else if value.Valid { u.Name = value.String } + case user.FieldRole: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field role", values[i]) + } else if value.Valid { + u.Role = user.Role(value.String) + } default: u.selectValues.Set(columns[i], values[i]) } @@ -95,6 +103,9 @@ func (u *User) String() string { builder.WriteString(fmt.Sprintf("id=%v, ", u.ID)) builder.WriteString("name=") builder.WriteString(u.Name) + builder.WriteString(", ") + builder.WriteString("role=") + builder.WriteString(fmt.Sprintf("%v", u.Role)) builder.WriteByte(')') return builder.String() } diff --git a/ent/user/user.go b/ent/user/user.go index 28409e9..3d04946 100644 --- a/ent/user/user.go +++ b/ent/user/user.go @@ -3,6 +3,8 @@ package user import ( + "fmt" + "entgo.io/ent/dialect/sql" ) @@ -13,6 +15,8 @@ const ( FieldID = "id" // FieldName holds the string denoting the name field in the database. FieldName = "name" + // FieldRole holds the string denoting the role field in the database. + FieldRole = "role" // Table holds the table name of the user in the database. Table = "users" ) @@ -21,6 +25,7 @@ const ( var Columns = []string{ FieldID, FieldName, + FieldRole, } // ValidColumn reports if the column name is valid (part of the table columns). @@ -38,6 +43,30 @@ var ( DefaultName string ) +// Role defines the type for the "role" enum field. +type Role string + +// Role values. +const ( + RoleAdmin Role = "admin" + RoleUser Role = "user" + RoleVisitor Role = "visitor" +) + +func (r Role) String() string { + return string(r) +} + +// RoleValidator is a validator for the "role" field enum values. It is called by the builders before save. +func RoleValidator(r Role) error { + switch r { + case RoleAdmin, RoleUser, RoleVisitor: + return nil + default: + return fmt.Errorf("user: invalid enum value for role field: %q", r) + } +} + // OrderOption defines the ordering options for the User queries. type OrderOption func(*sql.Selector) @@ -50,3 +79,8 @@ func ByID(opts ...sql.OrderTermOption) OrderOption { func ByName(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldName, opts...).ToFunc() } + +// ByRole orders the results by the role field. +func ByRole(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldRole, opts...).ToFunc() +} diff --git a/ent/user/where.go b/ent/user/where.go index a81a01d..2ad1ae0 100644 --- a/ent/user/where.go +++ b/ent/user/where.go @@ -123,6 +123,26 @@ func NameContainsFold(v string) predicate.User { return predicate.User(sql.FieldContainsFold(FieldName, v)) } +// RoleEQ applies the EQ predicate on the "role" field. +func RoleEQ(v Role) predicate.User { + return predicate.User(sql.FieldEQ(FieldRole, v)) +} + +// RoleNEQ applies the NEQ predicate on the "role" field. +func RoleNEQ(v Role) predicate.User { + return predicate.User(sql.FieldNEQ(FieldRole, v)) +} + +// RoleIn applies the In predicate on the "role" field. +func RoleIn(vs ...Role) predicate.User { + return predicate.User(sql.FieldIn(FieldRole, vs...)) +} + +// RoleNotIn applies the NotIn predicate on the "role" field. +func RoleNotIn(vs ...Role) predicate.User { + return predicate.User(sql.FieldNotIn(FieldRole, vs...)) +} + // 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 0d50b51..53b3fbe 100644 --- a/ent/user_create.go +++ b/ent/user_create.go @@ -33,6 +33,12 @@ func (uc *UserCreate) SetNillableName(s *string) *UserCreate { return uc } +// SetRole sets the "role" field. +func (uc *UserCreate) SetRole(u user.Role) *UserCreate { + uc.mutation.SetRole(u) + return uc +} + // Mutation returns the UserMutation object of the builder. func (uc *UserCreate) Mutation() *UserMutation { return uc.mutation @@ -79,6 +85,14 @@ func (uc *UserCreate) check() error { if _, ok := uc.mutation.Name(); !ok { return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "User.name"`)} } + if _, ok := uc.mutation.Role(); !ok { + return &ValidationError{Name: "role", err: errors.New(`ent: missing required field "User.role"`)} + } + if v, ok := uc.mutation.Role(); ok { + if err := user.RoleValidator(v); err != nil { + return &ValidationError{Name: "role", err: fmt.Errorf(`ent: validator failed for field "User.role": %w`, err)} + } + } return nil } @@ -109,6 +123,10 @@ func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { _spec.SetField(user.FieldName, field.TypeString, value) _node.Name = value } + if value, ok := uc.mutation.Role(); ok { + _spec.SetField(user.FieldRole, field.TypeEnum, value) + _node.Role = value + } return _node, _spec } diff --git a/ent/user_update.go b/ent/user_update.go index 37da344..55ac668 100644 --- a/ent/user_update.go +++ b/ent/user_update.go @@ -41,6 +41,20 @@ func (uu *UserUpdate) SetNillableName(s *string) *UserUpdate { return uu } +// SetRole sets the "role" field. +func (uu *UserUpdate) SetRole(u user.Role) *UserUpdate { + uu.mutation.SetRole(u) + return uu +} + +// SetNillableRole sets the "role" field if the given value is not nil. +func (uu *UserUpdate) SetNillableRole(u *user.Role) *UserUpdate { + if u != nil { + uu.SetRole(*u) + } + return uu +} + // Mutation returns the UserMutation object of the builder. func (uu *UserUpdate) Mutation() *UserMutation { return uu.mutation @@ -73,7 +87,20 @@ func (uu *UserUpdate) ExecX(ctx context.Context) { } } +// check runs all checks and user-defined validators on the builder. +func (uu *UserUpdate) check() error { + if v, ok := uu.mutation.Role(); ok { + if err := user.RoleValidator(v); err != nil { + return &ValidationError{Name: "role", err: fmt.Errorf(`ent: validator failed for field "User.role": %w`, err)} + } + } + return nil +} + func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) { + if err := uu.check(); err != nil { + return n, err + } _spec := sqlgraph.NewUpdateSpec(user.Table, user.Columns, sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt)) if ps := uu.mutation.predicates; len(ps) > 0 { _spec.Predicate = func(selector *sql.Selector) { @@ -85,6 +112,9 @@ func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) { if value, ok := uu.mutation.Name(); ok { _spec.SetField(user.FieldName, field.TypeString, value) } + if value, ok := uu.mutation.Role(); ok { + _spec.SetField(user.FieldRole, field.TypeEnum, value) + } if n, err = sqlgraph.UpdateNodes(ctx, uu.driver, _spec); err != nil { if _, ok := err.(*sqlgraph.NotFoundError); ok { err = &NotFoundError{user.Label} @@ -119,6 +149,20 @@ func (uuo *UserUpdateOne) SetNillableName(s *string) *UserUpdateOne { return uuo } +// SetRole sets the "role" field. +func (uuo *UserUpdateOne) SetRole(u user.Role) *UserUpdateOne { + uuo.mutation.SetRole(u) + return uuo +} + +// SetNillableRole sets the "role" field if the given value is not nil. +func (uuo *UserUpdateOne) SetNillableRole(u *user.Role) *UserUpdateOne { + if u != nil { + uuo.SetRole(*u) + } + return uuo +} + // Mutation returns the UserMutation object of the builder. func (uuo *UserUpdateOne) Mutation() *UserMutation { return uuo.mutation @@ -164,7 +208,20 @@ func (uuo *UserUpdateOne) ExecX(ctx context.Context) { } } +// check runs all checks and user-defined validators on the builder. +func (uuo *UserUpdateOne) check() error { + if v, ok := uuo.mutation.Role(); ok { + if err := user.RoleValidator(v); err != nil { + return &ValidationError{Name: "role", err: fmt.Errorf(`ent: validator failed for field "User.role": %w`, err)} + } + } + return nil +} + func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) { + if err := uuo.check(); err != nil { + return _node, err + } _spec := sqlgraph.NewUpdateSpec(user.Table, user.Columns, sqlgraph.NewFieldSpec(user.FieldID, field.TypeInt)) id, ok := uuo.mutation.ID() if !ok { @@ -193,6 +250,9 @@ func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) if value, ok := uuo.mutation.Name(); ok { _spec.SetField(user.FieldName, field.TypeString, value) } + if value, ok := uuo.mutation.Role(); ok { + _spec.SetField(user.FieldRole, field.TypeEnum, value) + } _node = &User{config: uuo.config} _spec.Assign = _node.assignValues _spec.ScanValues = _node.scanValues diff --git a/go.mod b/go.mod index de563c4..205a5d8 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.22 require ( entgo.io/ent v0.13.0 + github.com/go-sql-driver/mysql v1.7.1 github.com/joho/godotenv v1.5.1 ) @@ -12,7 +13,6 @@ require ( github.com/agext/levenshtein v1.2.3 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/go-openapi/inflect v0.19.0 // indirect - github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/hcl/v2 v2.19.1 // indirect