├── .gitignore ├── README.md ├── db ├── ent │ ├── client.go │ ├── config.go │ ├── context.go │ ├── ent.go │ ├── enttest │ │ └── enttest.go │ ├── generate.go │ ├── hook │ │ └── hook.go │ ├── migrate │ │ ├── migrate.go │ │ └── schema.go │ ├── mutation.go │ ├── predicate │ │ └── predicate.go │ ├── runtime.go │ ├── runtime │ │ └── runtime.go │ ├── schema │ │ ├── tourproduct.go │ │ └── user.go │ ├── tourproduct.go │ ├── tourproduct │ │ ├── tourproduct.go │ │ └── where.go │ ├── tourproduct_create.go │ ├── tourproduct_delete.go │ ├── tourproduct_query.go │ ├── tourproduct_update.go │ ├── tx.go │ ├── user.go │ ├── user │ │ ├── user.go │ │ └── where.go │ ├── user_create.go │ ├── user_delete.go │ ├── user_query.go │ └── user_update.go ├── go.mod ├── go.sum ├── main.go └── repository.go ├── errorhandle ├── go.mod ├── go.sum └── main.go ├── middleware ├── go.mod ├── go.sum └── main.go ├── testcode ├── datatypes.go ├── ent │ ├── client.go │ ├── config.go │ ├── context.go │ ├── ent.go │ ├── enttest │ │ └── enttest.go │ ├── generate.go │ ├── hook │ │ └── hook.go │ ├── migrate │ │ ├── migrate.go │ │ └── schema.go │ ├── mutation.go │ ├── predicate │ │ └── predicate.go │ ├── runtime.go │ ├── runtime │ │ └── runtime.go │ ├── schema │ │ └── user.go │ ├── tx.go │ ├── user.go │ ├── user │ │ ├── user.go │ │ └── where.go │ ├── user_create.go │ ├── user_delete.go │ ├── user_query.go │ └── user_update.go ├── go.mod ├── go.sum ├── gomock.go ├── main.go ├── mock.sh ├── mock_UserRepository.go ├── repository.go ├── service.go ├── service_test.go └── test.go └── webapp ├── go.mod ├── go.sum └── main.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | .idea 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Golang으로 백엔드 개발하기 2 | 3 | ## 1. 데이터베이스 작업하기 (Ent 프레임워크 이용) 4 | 5 | * 블로그 글: https://umi0410.github.io/blog/golang/how-to-backend-in-go-db 6 | 7 | * 코드: [db](db) 8 | 9 | ## 2. 테스트 코드 작성해보기 10 | 11 | * 블로그 글: https://umi0410.github.io/blog/golang/how-to-backend-in-go-testcode 12 | 13 | * 코드: [testcode](testcode) 14 | 15 | ## 3. 웹 프레임워크를 통해 웹 애플리케이션 개발하기 (fiber 프레임워크 이용) 16 | 17 | * 블로그 글: https://umi0410.github.io/blog/golang/how-to-backend-in-go-webapp 18 | 19 | * 코드: [webapp](webapp) 20 | 21 | ## 4. 미들웨어 22 | 23 | * 블로그 글: https://umi0410.github.io/blog/golang/how-to-backend-in-go-middleware 24 | 25 | * 코드: [middleware](middleware) 26 | 27 | ## 5. 에러 핸들링 28 | 29 | * 블로그 글: https://umi0410.github.io/blog/golang/how-to-backend-in-go-errorhandle 30 | 31 | * 코드: [errorhandle](errorhandle) 32 | 33 | ## 6. gRPC로 간단한 채팅 개발하기 34 | 35 | ## 7. 설정 관리 및 배포하기 (docker, kubernetes) 36 | 37 | -------------------------------------------------------------------------------- /db/ent/client.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "log" 9 | 10 | "db/ent/migrate" 11 | 12 | "db/ent/tourproduct" 13 | "db/ent/user" 14 | 15 | "entgo.io/ent/dialect" 16 | "entgo.io/ent/dialect/sql" 17 | "entgo.io/ent/dialect/sql/sqlgraph" 18 | ) 19 | 20 | // Client is the client that holds all ent builders. 21 | type Client struct { 22 | config 23 | // Schema is the client for creating, migrating and dropping schema. 24 | Schema *migrate.Schema 25 | // TourProduct is the client for interacting with the TourProduct builders. 26 | TourProduct *TourProductClient 27 | // User is the client for interacting with the User builders. 28 | User *UserClient 29 | } 30 | 31 | // NewClient creates a new client configured with the given options. 32 | func NewClient(opts ...Option) *Client { 33 | cfg := config{log: log.Println, hooks: &hooks{}} 34 | cfg.options(opts...) 35 | client := &Client{config: cfg} 36 | client.init() 37 | return client 38 | } 39 | 40 | func (c *Client) init() { 41 | c.Schema = migrate.NewSchema(c.driver) 42 | c.TourProduct = NewTourProductClient(c.config) 43 | c.User = NewUserClient(c.config) 44 | } 45 | 46 | // Open opens a database/sql.DB specified by the driver name and 47 | // the data source name, and returns a new client attached to it. 48 | // Optional parameters can be added for configuring the client. 49 | func Open(driverName, dataSourceName string, options ...Option) (*Client, error) { 50 | switch driverName { 51 | case dialect.MySQL, dialect.Postgres, dialect.SQLite: 52 | drv, err := sql.Open(driverName, dataSourceName) 53 | if err != nil { 54 | return nil, err 55 | } 56 | return NewClient(append(options, Driver(drv))...), nil 57 | default: 58 | return nil, fmt.Errorf("unsupported driver: %q", driverName) 59 | } 60 | } 61 | 62 | // Tx returns a new transactional client. The provided context 63 | // is used until the transaction is committed or rolled back. 64 | func (c *Client) Tx(ctx context.Context) (*Tx, error) { 65 | if _, ok := c.driver.(*txDriver); ok { 66 | return nil, fmt.Errorf("ent: cannot start a transaction within a transaction") 67 | } 68 | tx, err := newTx(ctx, c.driver) 69 | if err != nil { 70 | return nil, fmt.Errorf("ent: starting a transaction: %w", err) 71 | } 72 | cfg := c.config 73 | cfg.driver = tx 74 | return &Tx{ 75 | ctx: ctx, 76 | config: cfg, 77 | TourProduct: NewTourProductClient(cfg), 78 | User: NewUserClient(cfg), 79 | }, nil 80 | } 81 | 82 | // BeginTx returns a transactional client with specified options. 83 | func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { 84 | if _, ok := c.driver.(*txDriver); ok { 85 | return nil, fmt.Errorf("ent: cannot start a transaction within a transaction") 86 | } 87 | tx, err := c.driver.(interface { 88 | BeginTx(context.Context, *sql.TxOptions) (dialect.Tx, error) 89 | }).BeginTx(ctx, opts) 90 | if err != nil { 91 | return nil, fmt.Errorf("ent: starting a transaction: %w", err) 92 | } 93 | cfg := c.config 94 | cfg.driver = &txDriver{tx: tx, drv: c.driver} 95 | return &Tx{ 96 | config: cfg, 97 | TourProduct: NewTourProductClient(cfg), 98 | User: NewUserClient(cfg), 99 | }, nil 100 | } 101 | 102 | // Debug returns a new debug-client. It's used to get verbose logging on specific operations. 103 | // 104 | // client.Debug(). 105 | // TourProduct. 106 | // Query(). 107 | // Count(ctx) 108 | // 109 | func (c *Client) Debug() *Client { 110 | if c.debug { 111 | return c 112 | } 113 | cfg := c.config 114 | cfg.driver = dialect.Debug(c.driver, c.log) 115 | client := &Client{config: cfg} 116 | client.init() 117 | return client 118 | } 119 | 120 | // Close closes the database connection and prevents new queries from starting. 121 | func (c *Client) Close() error { 122 | return c.driver.Close() 123 | } 124 | 125 | // Use adds the mutation hooks to all the entity clients. 126 | // In order to add hooks to a specific client, call: `client.Node.Use(...)`. 127 | func (c *Client) Use(hooks ...Hook) { 128 | c.TourProduct.Use(hooks...) 129 | c.User.Use(hooks...) 130 | } 131 | 132 | // TourProductClient is a client for the TourProduct schema. 133 | type TourProductClient struct { 134 | config 135 | } 136 | 137 | // NewTourProductClient returns a client for the TourProduct from the given config. 138 | func NewTourProductClient(c config) *TourProductClient { 139 | return &TourProductClient{config: c} 140 | } 141 | 142 | // Use adds a list of mutation hooks to the hooks stack. 143 | // A call to `Use(f, g, h)` equals to `tourproduct.Hooks(f(g(h())))`. 144 | func (c *TourProductClient) Use(hooks ...Hook) { 145 | c.hooks.TourProduct = append(c.hooks.TourProduct, hooks...) 146 | } 147 | 148 | // Create returns a create builder for TourProduct. 149 | func (c *TourProductClient) Create() *TourProductCreate { 150 | mutation := newTourProductMutation(c.config, OpCreate) 151 | return &TourProductCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} 152 | } 153 | 154 | // CreateBulk returns a builder for creating a bulk of TourProduct entities. 155 | func (c *TourProductClient) CreateBulk(builders ...*TourProductCreate) *TourProductCreateBulk { 156 | return &TourProductCreateBulk{config: c.config, builders: builders} 157 | } 158 | 159 | // Update returns an update builder for TourProduct. 160 | func (c *TourProductClient) Update() *TourProductUpdate { 161 | mutation := newTourProductMutation(c.config, OpUpdate) 162 | return &TourProductUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} 163 | } 164 | 165 | // UpdateOne returns an update builder for the given entity. 166 | func (c *TourProductClient) UpdateOne(tp *TourProduct) *TourProductUpdateOne { 167 | mutation := newTourProductMutation(c.config, OpUpdateOne, withTourProduct(tp)) 168 | return &TourProductUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} 169 | } 170 | 171 | // UpdateOneID returns an update builder for the given id. 172 | func (c *TourProductClient) UpdateOneID(id int) *TourProductUpdateOne { 173 | mutation := newTourProductMutation(c.config, OpUpdateOne, withTourProductID(id)) 174 | return &TourProductUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} 175 | } 176 | 177 | // Delete returns a delete builder for TourProduct. 178 | func (c *TourProductClient) Delete() *TourProductDelete { 179 | mutation := newTourProductMutation(c.config, OpDelete) 180 | return &TourProductDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} 181 | } 182 | 183 | // DeleteOne returns a delete builder for the given entity. 184 | func (c *TourProductClient) DeleteOne(tp *TourProduct) *TourProductDeleteOne { 185 | return c.DeleteOneID(tp.ID) 186 | } 187 | 188 | // DeleteOneID returns a delete builder for the given id. 189 | func (c *TourProductClient) DeleteOneID(id int) *TourProductDeleteOne { 190 | builder := c.Delete().Where(tourproduct.ID(id)) 191 | builder.mutation.id = &id 192 | builder.mutation.op = OpDeleteOne 193 | return &TourProductDeleteOne{builder} 194 | } 195 | 196 | // Query returns a query builder for TourProduct. 197 | func (c *TourProductClient) Query() *TourProductQuery { 198 | return &TourProductQuery{ 199 | config: c.config, 200 | } 201 | } 202 | 203 | // Get returns a TourProduct entity by its id. 204 | func (c *TourProductClient) Get(ctx context.Context, id int) (*TourProduct, error) { 205 | return c.Query().Where(tourproduct.ID(id)).Only(ctx) 206 | } 207 | 208 | // GetX is like Get, but panics if an error occurs. 209 | func (c *TourProductClient) GetX(ctx context.Context, id int) *TourProduct { 210 | obj, err := c.Get(ctx, id) 211 | if err != nil { 212 | panic(err) 213 | } 214 | return obj 215 | } 216 | 217 | // QueryManager queries the manager edge of a TourProduct. 218 | func (c *TourProductClient) QueryManager(tp *TourProduct) *UserQuery { 219 | query := &UserQuery{config: c.config} 220 | query.path = func(ctx context.Context) (fromV *sql.Selector, _ error) { 221 | id := tp.ID 222 | step := sqlgraph.NewStep( 223 | sqlgraph.From(tourproduct.Table, tourproduct.FieldID, id), 224 | sqlgraph.To(user.Table, user.FieldID), 225 | sqlgraph.Edge(sqlgraph.M2O, true, tourproduct.ManagerTable, tourproduct.ManagerColumn), 226 | ) 227 | fromV = sqlgraph.Neighbors(tp.driver.Dialect(), step) 228 | return fromV, nil 229 | } 230 | return query 231 | } 232 | 233 | // Hooks returns the client hooks. 234 | func (c *TourProductClient) Hooks() []Hook { 235 | return c.hooks.TourProduct 236 | } 237 | 238 | // UserClient is a client for the User schema. 239 | type UserClient struct { 240 | config 241 | } 242 | 243 | // NewUserClient returns a client for the User from the given config. 244 | func NewUserClient(c config) *UserClient { 245 | return &UserClient{config: c} 246 | } 247 | 248 | // Use adds a list of mutation hooks to the hooks stack. 249 | // A call to `Use(f, g, h)` equals to `user.Hooks(f(g(h())))`. 250 | func (c *UserClient) Use(hooks ...Hook) { 251 | c.hooks.User = append(c.hooks.User, hooks...) 252 | } 253 | 254 | // Create returns a create builder for User. 255 | func (c *UserClient) Create() *UserCreate { 256 | mutation := newUserMutation(c.config, OpCreate) 257 | return &UserCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} 258 | } 259 | 260 | // CreateBulk returns a builder for creating a bulk of User entities. 261 | func (c *UserClient) CreateBulk(builders ...*UserCreate) *UserCreateBulk { 262 | return &UserCreateBulk{config: c.config, builders: builders} 263 | } 264 | 265 | // Update returns an update builder for User. 266 | func (c *UserClient) Update() *UserUpdate { 267 | mutation := newUserMutation(c.config, OpUpdate) 268 | return &UserUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} 269 | } 270 | 271 | // UpdateOne returns an update builder for the given entity. 272 | func (c *UserClient) UpdateOne(u *User) *UserUpdateOne { 273 | mutation := newUserMutation(c.config, OpUpdateOne, withUser(u)) 274 | return &UserUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} 275 | } 276 | 277 | // UpdateOneID returns an update builder for the given id. 278 | func (c *UserClient) UpdateOneID(id string) *UserUpdateOne { 279 | mutation := newUserMutation(c.config, OpUpdateOne, withUserID(id)) 280 | return &UserUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} 281 | } 282 | 283 | // Delete returns a delete builder for User. 284 | func (c *UserClient) Delete() *UserDelete { 285 | mutation := newUserMutation(c.config, OpDelete) 286 | return &UserDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} 287 | } 288 | 289 | // DeleteOne returns a delete builder for the given entity. 290 | func (c *UserClient) DeleteOne(u *User) *UserDeleteOne { 291 | return c.DeleteOneID(u.ID) 292 | } 293 | 294 | // DeleteOneID returns a delete builder for the given id. 295 | func (c *UserClient) DeleteOneID(id string) *UserDeleteOne { 296 | builder := c.Delete().Where(user.ID(id)) 297 | builder.mutation.id = &id 298 | builder.mutation.op = OpDeleteOne 299 | return &UserDeleteOne{builder} 300 | } 301 | 302 | // Query returns a query builder for User. 303 | func (c *UserClient) Query() *UserQuery { 304 | return &UserQuery{ 305 | config: c.config, 306 | } 307 | } 308 | 309 | // Get returns a User entity by its id. 310 | func (c *UserClient) Get(ctx context.Context, id string) (*User, error) { 311 | return c.Query().Where(user.ID(id)).Only(ctx) 312 | } 313 | 314 | // GetX is like Get, but panics if an error occurs. 315 | func (c *UserClient) GetX(ctx context.Context, id string) *User { 316 | obj, err := c.Get(ctx, id) 317 | if err != nil { 318 | panic(err) 319 | } 320 | return obj 321 | } 322 | 323 | // QueryProducts queries the products edge of a User. 324 | func (c *UserClient) QueryProducts(u *User) *TourProductQuery { 325 | query := &TourProductQuery{config: c.config} 326 | query.path = func(ctx context.Context) (fromV *sql.Selector, _ error) { 327 | id := u.ID 328 | step := sqlgraph.NewStep( 329 | sqlgraph.From(user.Table, user.FieldID, id), 330 | sqlgraph.To(tourproduct.Table, tourproduct.FieldID), 331 | sqlgraph.Edge(sqlgraph.O2M, false, user.ProductsTable, user.ProductsColumn), 332 | ) 333 | fromV = sqlgraph.Neighbors(u.driver.Dialect(), step) 334 | return fromV, nil 335 | } 336 | return query 337 | } 338 | 339 | // Hooks returns the client hooks. 340 | func (c *UserClient) Hooks() []Hook { 341 | return c.hooks.User 342 | } 343 | -------------------------------------------------------------------------------- /db/ent/config.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "entgo.io/ent" 7 | "entgo.io/ent/dialect" 8 | ) 9 | 10 | // Option function to configure the client. 11 | type Option func(*config) 12 | 13 | // Config is the configuration for the client and its builder. 14 | type config struct { 15 | // driver used for executing database requests. 16 | driver dialect.Driver 17 | // debug enable a debug logging. 18 | debug bool 19 | // log used for logging on debug mode. 20 | log func(...interface{}) 21 | // hooks to execute on mutations. 22 | hooks *hooks 23 | } 24 | 25 | // hooks per client, for fast access. 26 | type hooks struct { 27 | TourProduct []ent.Hook 28 | User []ent.Hook 29 | } 30 | 31 | // Options applies the options on the config object. 32 | func (c *config) options(opts ...Option) { 33 | for _, opt := range opts { 34 | opt(c) 35 | } 36 | if c.debug { 37 | c.driver = dialect.Debug(c.driver, c.log) 38 | } 39 | } 40 | 41 | // Debug enables debug logging on the ent.Driver. 42 | func Debug() Option { 43 | return func(c *config) { 44 | c.debug = true 45 | } 46 | } 47 | 48 | // Log sets the logging function for debug mode. 49 | func Log(fn func(...interface{})) Option { 50 | return func(c *config) { 51 | c.log = fn 52 | } 53 | } 54 | 55 | // Driver configures the client driver. 56 | func Driver(driver dialect.Driver) Option { 57 | return func(c *config) { 58 | c.driver = driver 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /db/ent/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | ) 8 | 9 | type clientCtxKey struct{} 10 | 11 | // FromContext returns a Client stored inside a context, or nil if there isn't one. 12 | func FromContext(ctx context.Context) *Client { 13 | c, _ := ctx.Value(clientCtxKey{}).(*Client) 14 | return c 15 | } 16 | 17 | // NewContext returns a new context with the given Client attached. 18 | func NewContext(parent context.Context, c *Client) context.Context { 19 | return context.WithValue(parent, clientCtxKey{}, c) 20 | } 21 | 22 | type txCtxKey struct{} 23 | 24 | // TxFromContext returns a Tx stored inside a context, or nil if there isn't one. 25 | func TxFromContext(ctx context.Context) *Tx { 26 | tx, _ := ctx.Value(txCtxKey{}).(*Tx) 27 | return tx 28 | } 29 | 30 | // NewTxContext returns a new context with the given Tx attached. 31 | func NewTxContext(parent context.Context, tx *Tx) context.Context { 32 | return context.WithValue(parent, txCtxKey{}, tx) 33 | } 34 | -------------------------------------------------------------------------------- /db/ent/ent.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "db/ent/tourproduct" 7 | "db/ent/user" 8 | "errors" 9 | "fmt" 10 | 11 | "entgo.io/ent" 12 | "entgo.io/ent/dialect" 13 | "entgo.io/ent/dialect/sql" 14 | "entgo.io/ent/dialect/sql/sqlgraph" 15 | ) 16 | 17 | // ent aliases to avoid import conflicts in user's code. 18 | type ( 19 | Op = ent.Op 20 | Hook = ent.Hook 21 | Value = ent.Value 22 | Query = ent.Query 23 | Policy = ent.Policy 24 | Mutator = ent.Mutator 25 | Mutation = ent.Mutation 26 | MutateFunc = ent.MutateFunc 27 | ) 28 | 29 | // OrderFunc applies an ordering on the sql selector. 30 | type OrderFunc func(*sql.Selector) 31 | 32 | // columnChecker returns a function indicates if the column exists in the given column. 33 | func columnChecker(table string) func(string) error { 34 | checks := map[string]func(string) bool{ 35 | tourproduct.Table: tourproduct.ValidColumn, 36 | user.Table: user.ValidColumn, 37 | } 38 | check, ok := checks[table] 39 | if !ok { 40 | return func(string) error { 41 | return fmt.Errorf("unknown table %q", table) 42 | } 43 | } 44 | return func(column string) error { 45 | if !check(column) { 46 | return fmt.Errorf("unknown column %q for table %q", column, table) 47 | } 48 | return nil 49 | } 50 | } 51 | 52 | // Asc applies the given fields in ASC order. 53 | func Asc(fields ...string) OrderFunc { 54 | return func(s *sql.Selector) { 55 | check := columnChecker(s.TableName()) 56 | for _, f := range fields { 57 | if err := check(f); err != nil { 58 | s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)}) 59 | } 60 | s.OrderBy(sql.Asc(s.C(f))) 61 | } 62 | } 63 | } 64 | 65 | // Desc applies the given fields in DESC order. 66 | func Desc(fields ...string) OrderFunc { 67 | return func(s *sql.Selector) { 68 | check := columnChecker(s.TableName()) 69 | for _, f := range fields { 70 | if err := check(f); err != nil { 71 | s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)}) 72 | } 73 | s.OrderBy(sql.Desc(s.C(f))) 74 | } 75 | } 76 | } 77 | 78 | // AggregateFunc applies an aggregation step on the group-by traversal/selector. 79 | type AggregateFunc func(*sql.Selector) string 80 | 81 | // As is a pseudo aggregation function for renaming another other functions with custom names. For example: 82 | // 83 | // GroupBy(field1, field2). 84 | // Aggregate(ent.As(ent.Sum(field1), "sum_field1"), (ent.As(ent.Sum(field2), "sum_field2")). 85 | // Scan(ctx, &v) 86 | // 87 | func As(fn AggregateFunc, end string) AggregateFunc { 88 | return func(s *sql.Selector) string { 89 | return sql.As(fn(s), end) 90 | } 91 | } 92 | 93 | // Count applies the "count" aggregation function on each group. 94 | func Count() AggregateFunc { 95 | return func(s *sql.Selector) string { 96 | return sql.Count("*") 97 | } 98 | } 99 | 100 | // Max applies the "max" aggregation function on the given field of each group. 101 | func Max(field string) AggregateFunc { 102 | return func(s *sql.Selector) string { 103 | check := columnChecker(s.TableName()) 104 | if err := check(field); err != nil { 105 | s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) 106 | return "" 107 | } 108 | return sql.Max(s.C(field)) 109 | } 110 | } 111 | 112 | // Mean applies the "mean" aggregation function on the given field of each group. 113 | func Mean(field string) AggregateFunc { 114 | return func(s *sql.Selector) string { 115 | check := columnChecker(s.TableName()) 116 | if err := check(field); err != nil { 117 | s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) 118 | return "" 119 | } 120 | return sql.Avg(s.C(field)) 121 | } 122 | } 123 | 124 | // Min applies the "min" aggregation function on the given field of each group. 125 | func Min(field string) AggregateFunc { 126 | return func(s *sql.Selector) string { 127 | check := columnChecker(s.TableName()) 128 | if err := check(field); err != nil { 129 | s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) 130 | return "" 131 | } 132 | return sql.Min(s.C(field)) 133 | } 134 | } 135 | 136 | // Sum applies the "sum" aggregation function on the given field of each group. 137 | func Sum(field string) AggregateFunc { 138 | return func(s *sql.Selector) string { 139 | check := columnChecker(s.TableName()) 140 | if err := check(field); err != nil { 141 | s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) 142 | return "" 143 | } 144 | return sql.Sum(s.C(field)) 145 | } 146 | } 147 | 148 | // ValidationError returns when validating a field fails. 149 | type ValidationError struct { 150 | Name string // Field or edge name. 151 | err error 152 | } 153 | 154 | // Error implements the error interface. 155 | func (e *ValidationError) Error() string { 156 | return e.err.Error() 157 | } 158 | 159 | // Unwrap implements the errors.Wrapper interface. 160 | func (e *ValidationError) Unwrap() error { 161 | return e.err 162 | } 163 | 164 | // IsValidationError returns a boolean indicating whether the error is a validaton error. 165 | func IsValidationError(err error) bool { 166 | if err == nil { 167 | return false 168 | } 169 | var e *ValidationError 170 | return errors.As(err, &e) 171 | } 172 | 173 | // NotFoundError returns when trying to fetch a specific entity and it was not found in the database. 174 | type NotFoundError struct { 175 | label string 176 | } 177 | 178 | // Error implements the error interface. 179 | func (e *NotFoundError) Error() string { 180 | return "ent: " + e.label + " not found" 181 | } 182 | 183 | // IsNotFound returns a boolean indicating whether the error is a not found error. 184 | func IsNotFound(err error) bool { 185 | if err == nil { 186 | return false 187 | } 188 | var e *NotFoundError 189 | return errors.As(err, &e) 190 | } 191 | 192 | // MaskNotFound masks not found error. 193 | func MaskNotFound(err error) error { 194 | if IsNotFound(err) { 195 | return nil 196 | } 197 | return err 198 | } 199 | 200 | // NotSingularError returns when trying to fetch a singular entity and more then one was found in the database. 201 | type NotSingularError struct { 202 | label string 203 | } 204 | 205 | // Error implements the error interface. 206 | func (e *NotSingularError) Error() string { 207 | return "ent: " + e.label + " not singular" 208 | } 209 | 210 | // IsNotSingular returns a boolean indicating whether the error is a not singular error. 211 | func IsNotSingular(err error) bool { 212 | if err == nil { 213 | return false 214 | } 215 | var e *NotSingularError 216 | return errors.As(err, &e) 217 | } 218 | 219 | // NotLoadedError returns when trying to get a node that was not loaded by the query. 220 | type NotLoadedError struct { 221 | edge string 222 | } 223 | 224 | // Error implements the error interface. 225 | func (e *NotLoadedError) Error() string { 226 | return "ent: " + e.edge + " edge was not loaded" 227 | } 228 | 229 | // IsNotLoaded returns a boolean indicating whether the error is a not loaded error. 230 | func IsNotLoaded(err error) bool { 231 | if err == nil { 232 | return false 233 | } 234 | var e *NotLoadedError 235 | return errors.As(err, &e) 236 | } 237 | 238 | // ConstraintError returns when trying to create/update one or more entities and 239 | // one or more of their constraints failed. For example, violation of edge or 240 | // field uniqueness. 241 | type ConstraintError struct { 242 | msg string 243 | wrap error 244 | } 245 | 246 | // Error implements the error interface. 247 | func (e ConstraintError) Error() string { 248 | return "ent: constraint failed: " + e.msg 249 | } 250 | 251 | // Unwrap implements the errors.Wrapper interface. 252 | func (e *ConstraintError) Unwrap() error { 253 | return e.wrap 254 | } 255 | 256 | // IsConstraintError returns a boolean indicating whether the error is a constraint failure. 257 | func IsConstraintError(err error) bool { 258 | if err == nil { 259 | return false 260 | } 261 | var e *ConstraintError 262 | return errors.As(err, &e) 263 | } 264 | 265 | func isSQLConstraintError(err error) (*ConstraintError, bool) { 266 | if sqlgraph.IsConstraintError(err) { 267 | return &ConstraintError{err.Error(), err}, true 268 | } 269 | return nil, false 270 | } 271 | 272 | // rollback calls tx.Rollback and wraps the given error with the rollback error if present. 273 | func rollback(tx dialect.Tx, err error) error { 274 | if rerr := tx.Rollback(); rerr != nil { 275 | err = fmt.Errorf("%w: %v", err, rerr) 276 | } 277 | if err, ok := isSQLConstraintError(err); ok { 278 | return err 279 | } 280 | return err 281 | } 282 | -------------------------------------------------------------------------------- /db/ent/enttest/enttest.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package enttest 4 | 5 | import ( 6 | "context" 7 | "db/ent" 8 | // required by schema hooks. 9 | _ "db/ent/runtime" 10 | 11 | "entgo.io/ent/dialect/sql/schema" 12 | ) 13 | 14 | type ( 15 | // TestingT is the interface that is shared between 16 | // testing.T and testing.B and used by enttest. 17 | TestingT interface { 18 | FailNow() 19 | Error(...interface{}) 20 | } 21 | 22 | // Option configures client creation. 23 | Option func(*options) 24 | 25 | options struct { 26 | opts []ent.Option 27 | migrateOpts []schema.MigrateOption 28 | } 29 | ) 30 | 31 | // WithOptions forwards options to client creation. 32 | func WithOptions(opts ...ent.Option) Option { 33 | return func(o *options) { 34 | o.opts = append(o.opts, opts...) 35 | } 36 | } 37 | 38 | // WithMigrateOptions forwards options to auto migration. 39 | func WithMigrateOptions(opts ...schema.MigrateOption) Option { 40 | return func(o *options) { 41 | o.migrateOpts = append(o.migrateOpts, opts...) 42 | } 43 | } 44 | 45 | func newOptions(opts []Option) *options { 46 | o := &options{} 47 | for _, opt := range opts { 48 | opt(o) 49 | } 50 | return o 51 | } 52 | 53 | // Open calls ent.Open and auto-run migration. 54 | func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client { 55 | o := newOptions(opts) 56 | c, err := ent.Open(driverName, dataSourceName, o.opts...) 57 | if err != nil { 58 | t.Error(err) 59 | t.FailNow() 60 | } 61 | if err := c.Schema.Create(context.Background(), o.migrateOpts...); err != nil { 62 | t.Error(err) 63 | t.FailNow() 64 | } 65 | return c 66 | } 67 | 68 | // NewClient calls ent.NewClient and auto-run migration. 69 | func NewClient(t TestingT, opts ...Option) *ent.Client { 70 | o := newOptions(opts) 71 | c := ent.NewClient(o.opts...) 72 | if err := c.Schema.Create(context.Background(), o.migrateOpts...); err != nil { 73 | t.Error(err) 74 | t.FailNow() 75 | } 76 | return c 77 | } 78 | -------------------------------------------------------------------------------- /db/ent/generate.go: -------------------------------------------------------------------------------- 1 | package ent 2 | 3 | //go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema 4 | -------------------------------------------------------------------------------- /db/ent/hook/hook.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package hook 4 | 5 | import ( 6 | "context" 7 | "db/ent" 8 | "fmt" 9 | ) 10 | 11 | // The TourProductFunc type is an adapter to allow the use of ordinary 12 | // function as TourProduct mutator. 13 | type TourProductFunc func(context.Context, *ent.TourProductMutation) (ent.Value, error) 14 | 15 | // Mutate calls f(ctx, m). 16 | func (f TourProductFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { 17 | mv, ok := m.(*ent.TourProductMutation) 18 | if !ok { 19 | return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.TourProductMutation", m) 20 | } 21 | return f(ctx, mv) 22 | } 23 | 24 | // The UserFunc type is an adapter to allow the use of ordinary 25 | // function as User mutator. 26 | type UserFunc func(context.Context, *ent.UserMutation) (ent.Value, error) 27 | 28 | // Mutate calls f(ctx, m). 29 | func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { 30 | mv, ok := m.(*ent.UserMutation) 31 | if !ok { 32 | return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.UserMutation", m) 33 | } 34 | return f(ctx, mv) 35 | } 36 | 37 | // Condition is a hook condition function. 38 | type Condition func(context.Context, ent.Mutation) bool 39 | 40 | // And groups conditions with the AND operator. 41 | func And(first, second Condition, rest ...Condition) Condition { 42 | return func(ctx context.Context, m ent.Mutation) bool { 43 | if !first(ctx, m) || !second(ctx, m) { 44 | return false 45 | } 46 | for _, cond := range rest { 47 | if !cond(ctx, m) { 48 | return false 49 | } 50 | } 51 | return true 52 | } 53 | } 54 | 55 | // Or groups conditions with the OR operator. 56 | func Or(first, second Condition, rest ...Condition) Condition { 57 | return func(ctx context.Context, m ent.Mutation) bool { 58 | if first(ctx, m) || second(ctx, m) { 59 | return true 60 | } 61 | for _, cond := range rest { 62 | if cond(ctx, m) { 63 | return true 64 | } 65 | } 66 | return false 67 | } 68 | } 69 | 70 | // Not negates a given condition. 71 | func Not(cond Condition) Condition { 72 | return func(ctx context.Context, m ent.Mutation) bool { 73 | return !cond(ctx, m) 74 | } 75 | } 76 | 77 | // HasOp is a condition testing mutation operation. 78 | func HasOp(op ent.Op) Condition { 79 | return func(_ context.Context, m ent.Mutation) bool { 80 | return m.Op().Is(op) 81 | } 82 | } 83 | 84 | // HasAddedFields is a condition validating `.AddedField` on fields. 85 | func HasAddedFields(field string, fields ...string) Condition { 86 | return func(_ context.Context, m ent.Mutation) bool { 87 | if _, exists := m.AddedField(field); !exists { 88 | return false 89 | } 90 | for _, field := range fields { 91 | if _, exists := m.AddedField(field); !exists { 92 | return false 93 | } 94 | } 95 | return true 96 | } 97 | } 98 | 99 | // HasClearedFields is a condition validating `.FieldCleared` on fields. 100 | func HasClearedFields(field string, fields ...string) Condition { 101 | return func(_ context.Context, m ent.Mutation) bool { 102 | if exists := m.FieldCleared(field); !exists { 103 | return false 104 | } 105 | for _, field := range fields { 106 | if exists := m.FieldCleared(field); !exists { 107 | return false 108 | } 109 | } 110 | return true 111 | } 112 | } 113 | 114 | // HasFields is a condition validating `.Field` on fields. 115 | func HasFields(field string, fields ...string) Condition { 116 | return func(_ context.Context, m ent.Mutation) bool { 117 | if _, exists := m.Field(field); !exists { 118 | return false 119 | } 120 | for _, field := range fields { 121 | if _, exists := m.Field(field); !exists { 122 | return false 123 | } 124 | } 125 | return true 126 | } 127 | } 128 | 129 | // If executes the given hook under condition. 130 | // 131 | // hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) 132 | // 133 | func If(hk ent.Hook, cond Condition) ent.Hook { 134 | return func(next ent.Mutator) ent.Mutator { 135 | return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { 136 | if cond(ctx, m) { 137 | return hk(next).Mutate(ctx, m) 138 | } 139 | return next.Mutate(ctx, m) 140 | }) 141 | } 142 | } 143 | 144 | // On executes the given hook only for the given operation. 145 | // 146 | // hook.On(Log, ent.Delete|ent.Create) 147 | // 148 | func On(hk ent.Hook, op ent.Op) ent.Hook { 149 | return If(hk, HasOp(op)) 150 | } 151 | 152 | // Unless skips the given hook only for the given operation. 153 | // 154 | // hook.Unless(Log, ent.Update|ent.UpdateOne) 155 | // 156 | func Unless(hk ent.Hook, op ent.Op) ent.Hook { 157 | return If(hk, Not(HasOp(op))) 158 | } 159 | 160 | // FixedError is a hook returning a fixed error. 161 | func FixedError(err error) ent.Hook { 162 | return func(ent.Mutator) ent.Mutator { 163 | return ent.MutateFunc(func(context.Context, ent.Mutation) (ent.Value, error) { 164 | return nil, err 165 | }) 166 | } 167 | } 168 | 169 | // Reject returns a hook that rejects all operations that match op. 170 | // 171 | // func (T) Hooks() []ent.Hook { 172 | // return []ent.Hook{ 173 | // Reject(ent.Delete|ent.Update), 174 | // } 175 | // } 176 | // 177 | func Reject(op ent.Op) ent.Hook { 178 | hk := FixedError(fmt.Errorf("%s operation is not allowed", op)) 179 | return On(hk, op) 180 | } 181 | 182 | // Chain acts as a list of hooks and is effectively immutable. 183 | // Once created, it will always hold the same set of hooks in the same order. 184 | type Chain struct { 185 | hooks []ent.Hook 186 | } 187 | 188 | // NewChain creates a new chain of hooks. 189 | func NewChain(hooks ...ent.Hook) Chain { 190 | return Chain{append([]ent.Hook(nil), hooks...)} 191 | } 192 | 193 | // Hook chains the list of hooks and returns the final hook. 194 | func (c Chain) Hook() ent.Hook { 195 | return func(mutator ent.Mutator) ent.Mutator { 196 | for i := len(c.hooks) - 1; i >= 0; i-- { 197 | mutator = c.hooks[i](mutator) 198 | } 199 | return mutator 200 | } 201 | } 202 | 203 | // Append extends a chain, adding the specified hook 204 | // as the last ones in the mutation flow. 205 | func (c Chain) Append(hooks ...ent.Hook) Chain { 206 | newHooks := make([]ent.Hook, 0, len(c.hooks)+len(hooks)) 207 | newHooks = append(newHooks, c.hooks...) 208 | newHooks = append(newHooks, hooks...) 209 | return Chain{newHooks} 210 | } 211 | 212 | // Extend extends a chain, adding the specified chain 213 | // as the last ones in the mutation flow. 214 | func (c Chain) Extend(chain Chain) Chain { 215 | return c.Append(chain.hooks...) 216 | } 217 | -------------------------------------------------------------------------------- /db/ent/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package migrate 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "io" 9 | 10 | "entgo.io/ent/dialect" 11 | "entgo.io/ent/dialect/sql/schema" 12 | ) 13 | 14 | var ( 15 | // WithGlobalUniqueID sets the universal ids options to the migration. 16 | // If this option is enabled, ent migration will allocate a 1<<32 range 17 | // for the ids of each entity (table). 18 | // Note that this option cannot be applied on tables that already exist. 19 | WithGlobalUniqueID = schema.WithGlobalUniqueID 20 | // WithDropColumn sets the drop column option to the migration. 21 | // If this option is enabled, ent migration will drop old columns 22 | // that were used for both fields and edges. This defaults to false. 23 | WithDropColumn = schema.WithDropColumn 24 | // WithDropIndex sets the drop index option to the migration. 25 | // If this option is enabled, ent migration will drop old indexes 26 | // that were defined in the schema. This defaults to false. 27 | // Note that unique constraints are defined using `UNIQUE INDEX`, 28 | // and therefore, it's recommended to enable this option to get more 29 | // flexibility in the schema changes. 30 | WithDropIndex = schema.WithDropIndex 31 | // WithFixture sets the foreign-key renaming option to the migration when upgrading 32 | // ent from v0.1.0 (issue-#285). Defaults to false. 33 | WithFixture = schema.WithFixture 34 | // WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true. 35 | WithForeignKeys = schema.WithForeignKeys 36 | ) 37 | 38 | // Schema is the API for creating, migrating and dropping a schema. 39 | type Schema struct { 40 | drv dialect.Driver 41 | universalID bool 42 | } 43 | 44 | // NewSchema creates a new schema client. 45 | func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } 46 | 47 | // Create creates all schema resources. 48 | func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { 49 | migrate, err := schema.NewMigrate(s.drv, opts...) 50 | if err != nil { 51 | return fmt.Errorf("ent/migrate: %w", err) 52 | } 53 | return migrate.Create(ctx, Tables...) 54 | } 55 | 56 | // WriteTo writes the schema changes to w instead of running them against the database. 57 | // 58 | // if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { 59 | // log.Fatal(err) 60 | // } 61 | // 62 | func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { 63 | drv := &schema.WriteDriver{ 64 | Writer: w, 65 | Driver: s.drv, 66 | } 67 | migrate, err := schema.NewMigrate(drv, opts...) 68 | if err != nil { 69 | return fmt.Errorf("ent/migrate: %w", err) 70 | } 71 | return migrate.Create(ctx, Tables...) 72 | } 73 | -------------------------------------------------------------------------------- /db/ent/migrate/schema.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package migrate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql/schema" 7 | "entgo.io/ent/schema/field" 8 | ) 9 | 10 | var ( 11 | // TourProductsColumns holds the columns for the "tour_products" table. 12 | TourProductsColumns = []*schema.Column{ 13 | {Name: "id", Type: field.TypeInt, Increment: true}, 14 | {Name: "name", Type: field.TypeString}, 15 | {Name: "price", Type: field.TypeInt}, 16 | {Name: "for_sale", Type: field.TypeBool, Default: true}, 17 | {Name: "user_products", Type: field.TypeString, Nullable: true}, 18 | } 19 | // TourProductsTable holds the schema information for the "tour_products" table. 20 | TourProductsTable = &schema.Table{ 21 | Name: "tour_products", 22 | Columns: TourProductsColumns, 23 | PrimaryKey: []*schema.Column{TourProductsColumns[0]}, 24 | ForeignKeys: []*schema.ForeignKey{ 25 | { 26 | Symbol: "tour_products_users_products", 27 | Columns: []*schema.Column{TourProductsColumns[4]}, 28 | RefColumns: []*schema.Column{UsersColumns[0]}, 29 | OnDelete: schema.SetNull, 30 | }, 31 | }, 32 | } 33 | // UsersColumns holds the columns for the "users" table. 34 | UsersColumns = []*schema.Column{ 35 | {Name: "id", Type: field.TypeString}, 36 | {Name: "name", Type: field.TypeString}, 37 | {Name: "is_activated", Type: field.TypeBool, Default: true}, 38 | } 39 | // UsersTable holds the schema information for the "users" table. 40 | UsersTable = &schema.Table{ 41 | Name: "users", 42 | Columns: UsersColumns, 43 | PrimaryKey: []*schema.Column{UsersColumns[0]}, 44 | ForeignKeys: []*schema.ForeignKey{}, 45 | } 46 | // Tables holds all the tables in the schema. 47 | Tables = []*schema.Table{ 48 | TourProductsTable, 49 | UsersTable, 50 | } 51 | ) 52 | 53 | func init() { 54 | TourProductsTable.ForeignKeys[0].RefTable = UsersTable 55 | } 56 | -------------------------------------------------------------------------------- /db/ent/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package predicate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | ) 8 | 9 | // TourProduct is the predicate function for tourproduct builders. 10 | type TourProduct func(*sql.Selector) 11 | 12 | // User is the predicate function for user builders. 13 | type User func(*sql.Selector) 14 | -------------------------------------------------------------------------------- /db/ent/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "db/ent/schema" 7 | "db/ent/tourproduct" 8 | "db/ent/user" 9 | ) 10 | 11 | // The init function reads all schema descriptors with runtime code 12 | // (default values, validators, hooks and policies) and stitches it 13 | // to their package variables. 14 | func init() { 15 | tourproductFields := schema.TourProduct{}.Fields() 16 | _ = tourproductFields 17 | // tourproductDescForSale is the schema descriptor for forSale field. 18 | tourproductDescForSale := tourproductFields[2].Descriptor() 19 | // tourproduct.DefaultForSale holds the default value on creation for the forSale field. 20 | tourproduct.DefaultForSale = tourproductDescForSale.Default.(bool) 21 | userFields := schema.User{}.Fields() 22 | _ = userFields 23 | // userDescIsActivated is the schema descriptor for isActivated field. 24 | userDescIsActivated := userFields[2].Descriptor() 25 | // user.DefaultIsActivated holds the default value on creation for the isActivated field. 26 | user.DefaultIsActivated = userDescIsActivated.Default.(bool) 27 | } 28 | -------------------------------------------------------------------------------- /db/ent/runtime/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package runtime 4 | 5 | // The schema-stitching logic is generated in db/ent/runtime.go 6 | 7 | const ( 8 | Version = "v0.8.0" // Version of ent codegen. 9 | Sum = "h1:xirrW//1oda7pp0bz+XssSOv4/C3nmgYQOxjIfljFt8=" // Sum of ent codegen. 10 | ) 11 | -------------------------------------------------------------------------------- /db/ent/schema/tourproduct.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/schema/edge" 6 | "entgo.io/ent/schema/field" 7 | ) 8 | 9 | // TourProduct holds the schema definition for the TourProduct entity. 10 | type TourProduct struct { 11 | ent.Schema 12 | } 13 | 14 | // Fields of the TourProduct. 15 | func (TourProduct) Fields() []ent.Field { 16 | return []ent.Field{ 17 | field.String("name"), 18 | field.Int("price"), 19 | field.Bool("forSale").Default(true), 20 | } 21 | } 22 | 23 | // Edges of the TourProduct. 24 | func (TourProduct) Edges() []ent.Edge { 25 | return []ent.Edge{ 26 | edge.From("manager", User.Type). 27 | Ref("products"). 28 | Required(). 29 | Unique(), 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /db/ent/schema/user.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/schema/edge" 6 | "entgo.io/ent/schema/field" 7 | ) 8 | 9 | // User holds the schema definition for the User entity. 10 | type User struct { 11 | ent.Schema 12 | } 13 | 14 | // Fields of the User. 15 | func (User) Fields() []ent.Field { 16 | return []ent.Field{ 17 | // 타입을 기반으로 안전하고 편리하게 컬럼을 정의할 수 있습니다. 18 | field.String("id"), 19 | field.String("name"), 20 | field.Bool("isActivated").Default(true), 21 | } 22 | } 23 | 24 | // Edges of the User. 25 | func (User) Edges() []ent.Edge { 26 | return []ent.Edge{ 27 | // ent에서는 To를 정의하는 스키마, 즉 여기선 User 28 | // 가 참조 관계의 주인이라고 정의합니다. 29 | // 일반적인 JPA의 방식과는 반대입니다. 30 | edge.To("products", TourProduct.Type), 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /db/ent/tourproduct.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "db/ent/tourproduct" 7 | "db/ent/user" 8 | "fmt" 9 | "strings" 10 | 11 | "entgo.io/ent/dialect/sql" 12 | ) 13 | 14 | // TourProduct is the model entity for the TourProduct schema. 15 | type TourProduct struct { 16 | config `json:"-"` 17 | // ID of the ent. 18 | ID int `json:"id,omitempty"` 19 | // Name holds the value of the "name" field. 20 | Name string `json:"name,omitempty"` 21 | // Price holds the value of the "price" field. 22 | Price int `json:"price,omitempty"` 23 | // ForSale holds the value of the "forSale" field. 24 | ForSale bool `json:"forSale,omitempty"` 25 | // Edges holds the relations/edges for other nodes in the graph. 26 | // The values are being populated by the TourProductQuery when eager-loading is set. 27 | Edges TourProductEdges `json:"edges"` 28 | user_products *string 29 | } 30 | 31 | // TourProductEdges holds the relations/edges for other nodes in the graph. 32 | type TourProductEdges struct { 33 | // Manager holds the value of the manager edge. 34 | Manager *User `json:"manager,omitempty"` 35 | // loadedTypes holds the information for reporting if a 36 | // type was loaded (or requested) in eager-loading or not. 37 | loadedTypes [1]bool 38 | } 39 | 40 | // ManagerOrErr returns the Manager value or an error if the edge 41 | // was not loaded in eager-loading, or loaded but was not found. 42 | func (e TourProductEdges) ManagerOrErr() (*User, error) { 43 | if e.loadedTypes[0] { 44 | if e.Manager == nil { 45 | // The edge manager was loaded in eager-loading, 46 | // but was not found. 47 | return nil, &NotFoundError{label: user.Label} 48 | } 49 | return e.Manager, nil 50 | } 51 | return nil, &NotLoadedError{edge: "manager"} 52 | } 53 | 54 | // scanValues returns the types for scanning values from sql.Rows. 55 | func (*TourProduct) scanValues(columns []string) ([]interface{}, error) { 56 | values := make([]interface{}, len(columns)) 57 | for i := range columns { 58 | switch columns[i] { 59 | case tourproduct.FieldForSale: 60 | values[i] = new(sql.NullBool) 61 | case tourproduct.FieldID, tourproduct.FieldPrice: 62 | values[i] = new(sql.NullInt64) 63 | case tourproduct.FieldName: 64 | values[i] = new(sql.NullString) 65 | case tourproduct.ForeignKeys[0]: // user_products 66 | values[i] = new(sql.NullString) 67 | default: 68 | return nil, fmt.Errorf("unexpected column %q for type TourProduct", columns[i]) 69 | } 70 | } 71 | return values, nil 72 | } 73 | 74 | // assignValues assigns the values that were returned from sql.Rows (after scanning) 75 | // to the TourProduct fields. 76 | func (tp *TourProduct) assignValues(columns []string, values []interface{}) error { 77 | if m, n := len(values), len(columns); m < n { 78 | return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) 79 | } 80 | for i := range columns { 81 | switch columns[i] { 82 | case tourproduct.FieldID: 83 | value, ok := values[i].(*sql.NullInt64) 84 | if !ok { 85 | return fmt.Errorf("unexpected type %T for field id", value) 86 | } 87 | tp.ID = int(value.Int64) 88 | case tourproduct.FieldName: 89 | if value, ok := values[i].(*sql.NullString); !ok { 90 | return fmt.Errorf("unexpected type %T for field name", values[i]) 91 | } else if value.Valid { 92 | tp.Name = value.String 93 | } 94 | case tourproduct.FieldPrice: 95 | if value, ok := values[i].(*sql.NullInt64); !ok { 96 | return fmt.Errorf("unexpected type %T for field price", values[i]) 97 | } else if value.Valid { 98 | tp.Price = int(value.Int64) 99 | } 100 | case tourproduct.FieldForSale: 101 | if value, ok := values[i].(*sql.NullBool); !ok { 102 | return fmt.Errorf("unexpected type %T for field forSale", values[i]) 103 | } else if value.Valid { 104 | tp.ForSale = value.Bool 105 | } 106 | case tourproduct.ForeignKeys[0]: 107 | if value, ok := values[i].(*sql.NullString); !ok { 108 | return fmt.Errorf("unexpected type %T for field user_products", values[i]) 109 | } else if value.Valid { 110 | tp.user_products = new(string) 111 | *tp.user_products = value.String 112 | } 113 | } 114 | } 115 | return nil 116 | } 117 | 118 | // QueryManager queries the "manager" edge of the TourProduct entity. 119 | func (tp *TourProduct) QueryManager() *UserQuery { 120 | return (&TourProductClient{config: tp.config}).QueryManager(tp) 121 | } 122 | 123 | // Update returns a builder for updating this TourProduct. 124 | // Note that you need to call TourProduct.Unwrap() before calling this method if this TourProduct 125 | // was returned from a transaction, and the transaction was committed or rolled back. 126 | func (tp *TourProduct) Update() *TourProductUpdateOne { 127 | return (&TourProductClient{config: tp.config}).UpdateOne(tp) 128 | } 129 | 130 | // Unwrap unwraps the TourProduct entity that was returned from a transaction after it was closed, 131 | // so that all future queries will be executed through the driver which created the transaction. 132 | func (tp *TourProduct) Unwrap() *TourProduct { 133 | tx, ok := tp.config.driver.(*txDriver) 134 | if !ok { 135 | panic("ent: TourProduct is not a transactional entity") 136 | } 137 | tp.config.driver = tx.drv 138 | return tp 139 | } 140 | 141 | // String implements the fmt.Stringer. 142 | func (tp *TourProduct) String() string { 143 | var builder strings.Builder 144 | builder.WriteString("TourProduct(") 145 | builder.WriteString(fmt.Sprintf("id=%v", tp.ID)) 146 | builder.WriteString(", name=") 147 | builder.WriteString(tp.Name) 148 | builder.WriteString(", price=") 149 | builder.WriteString(fmt.Sprintf("%v", tp.Price)) 150 | builder.WriteString(", forSale=") 151 | builder.WriteString(fmt.Sprintf("%v", tp.ForSale)) 152 | builder.WriteByte(')') 153 | return builder.String() 154 | } 155 | 156 | // TourProducts is a parsable slice of TourProduct. 157 | type TourProducts []*TourProduct 158 | 159 | func (tp TourProducts) config(cfg config) { 160 | for _i := range tp { 161 | tp[_i].config = cfg 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /db/ent/tourproduct/tourproduct.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package tourproduct 4 | 5 | const ( 6 | // Label holds the string label denoting the tourproduct type in the database. 7 | Label = "tour_product" 8 | // FieldID holds the string denoting the id field in the database. 9 | FieldID = "id" 10 | // FieldName holds the string denoting the name field in the database. 11 | FieldName = "name" 12 | // FieldPrice holds the string denoting the price field in the database. 13 | FieldPrice = "price" 14 | // FieldForSale holds the string denoting the forsale field in the database. 15 | FieldForSale = "for_sale" 16 | // EdgeManager holds the string denoting the manager edge name in mutations. 17 | EdgeManager = "manager" 18 | // Table holds the table name of the tourproduct in the database. 19 | Table = "tour_products" 20 | // ManagerTable is the table the holds the manager relation/edge. 21 | ManagerTable = "tour_products" 22 | // ManagerInverseTable is the table name for the User entity. 23 | // It exists in this package in order to avoid circular dependency with the "user" package. 24 | ManagerInverseTable = "users" 25 | // ManagerColumn is the table column denoting the manager relation/edge. 26 | ManagerColumn = "user_products" 27 | ) 28 | 29 | // Columns holds all SQL columns for tourproduct fields. 30 | var Columns = []string{ 31 | FieldID, 32 | FieldName, 33 | FieldPrice, 34 | FieldForSale, 35 | } 36 | 37 | // ForeignKeys holds the SQL foreign-keys that are owned by the "tour_products" 38 | // table and are not defined as standalone fields in the schema. 39 | var ForeignKeys = []string{ 40 | "user_products", 41 | } 42 | 43 | // ValidColumn reports if the column name is valid (part of the table columns). 44 | func ValidColumn(column string) bool { 45 | for i := range Columns { 46 | if column == Columns[i] { 47 | return true 48 | } 49 | } 50 | for i := range ForeignKeys { 51 | if column == ForeignKeys[i] { 52 | return true 53 | } 54 | } 55 | return false 56 | } 57 | 58 | var ( 59 | // DefaultForSale holds the default value on creation for the "forSale" field. 60 | DefaultForSale bool 61 | ) 62 | -------------------------------------------------------------------------------- /db/ent/tourproduct/where.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package tourproduct 4 | 5 | import ( 6 | "db/ent/predicate" 7 | 8 | "entgo.io/ent/dialect/sql" 9 | "entgo.io/ent/dialect/sql/sqlgraph" 10 | ) 11 | 12 | // ID filters vertices based on their ID field. 13 | func ID(id int) predicate.TourProduct { 14 | return predicate.TourProduct(func(s *sql.Selector) { 15 | s.Where(sql.EQ(s.C(FieldID), id)) 16 | }) 17 | } 18 | 19 | // IDEQ applies the EQ predicate on the ID field. 20 | func IDEQ(id int) predicate.TourProduct { 21 | return predicate.TourProduct(func(s *sql.Selector) { 22 | s.Where(sql.EQ(s.C(FieldID), id)) 23 | }) 24 | } 25 | 26 | // IDNEQ applies the NEQ predicate on the ID field. 27 | func IDNEQ(id int) predicate.TourProduct { 28 | return predicate.TourProduct(func(s *sql.Selector) { 29 | s.Where(sql.NEQ(s.C(FieldID), id)) 30 | }) 31 | } 32 | 33 | // IDIn applies the In predicate on the ID field. 34 | func IDIn(ids ...int) predicate.TourProduct { 35 | return predicate.TourProduct(func(s *sql.Selector) { 36 | // if not arguments were provided, append the FALSE constants, 37 | // since we can't apply "IN ()". This will make this predicate falsy. 38 | if len(ids) == 0 { 39 | s.Where(sql.False()) 40 | return 41 | } 42 | v := make([]interface{}, len(ids)) 43 | for i := range v { 44 | v[i] = ids[i] 45 | } 46 | s.Where(sql.In(s.C(FieldID), v...)) 47 | }) 48 | } 49 | 50 | // IDNotIn applies the NotIn predicate on the ID field. 51 | func IDNotIn(ids ...int) predicate.TourProduct { 52 | return predicate.TourProduct(func(s *sql.Selector) { 53 | // if not arguments were provided, append the FALSE constants, 54 | // since we can't apply "IN ()". This will make this predicate falsy. 55 | if len(ids) == 0 { 56 | s.Where(sql.False()) 57 | return 58 | } 59 | v := make([]interface{}, len(ids)) 60 | for i := range v { 61 | v[i] = ids[i] 62 | } 63 | s.Where(sql.NotIn(s.C(FieldID), v...)) 64 | }) 65 | } 66 | 67 | // IDGT applies the GT predicate on the ID field. 68 | func IDGT(id int) predicate.TourProduct { 69 | return predicate.TourProduct(func(s *sql.Selector) { 70 | s.Where(sql.GT(s.C(FieldID), id)) 71 | }) 72 | } 73 | 74 | // IDGTE applies the GTE predicate on the ID field. 75 | func IDGTE(id int) predicate.TourProduct { 76 | return predicate.TourProduct(func(s *sql.Selector) { 77 | s.Where(sql.GTE(s.C(FieldID), id)) 78 | }) 79 | } 80 | 81 | // IDLT applies the LT predicate on the ID field. 82 | func IDLT(id int) predicate.TourProduct { 83 | return predicate.TourProduct(func(s *sql.Selector) { 84 | s.Where(sql.LT(s.C(FieldID), id)) 85 | }) 86 | } 87 | 88 | // IDLTE applies the LTE predicate on the ID field. 89 | func IDLTE(id int) predicate.TourProduct { 90 | return predicate.TourProduct(func(s *sql.Selector) { 91 | s.Where(sql.LTE(s.C(FieldID), id)) 92 | }) 93 | } 94 | 95 | // Name applies equality check predicate on the "name" field. It's identical to NameEQ. 96 | func Name(v string) predicate.TourProduct { 97 | return predicate.TourProduct(func(s *sql.Selector) { 98 | s.Where(sql.EQ(s.C(FieldName), v)) 99 | }) 100 | } 101 | 102 | // Price applies equality check predicate on the "price" field. It's identical to PriceEQ. 103 | func Price(v int) predicate.TourProduct { 104 | return predicate.TourProduct(func(s *sql.Selector) { 105 | s.Where(sql.EQ(s.C(FieldPrice), v)) 106 | }) 107 | } 108 | 109 | // ForSale applies equality check predicate on the "forSale" field. It's identical to ForSaleEQ. 110 | func ForSale(v bool) predicate.TourProduct { 111 | return predicate.TourProduct(func(s *sql.Selector) { 112 | s.Where(sql.EQ(s.C(FieldForSale), v)) 113 | }) 114 | } 115 | 116 | // NameEQ applies the EQ predicate on the "name" field. 117 | func NameEQ(v string) predicate.TourProduct { 118 | return predicate.TourProduct(func(s *sql.Selector) { 119 | s.Where(sql.EQ(s.C(FieldName), v)) 120 | }) 121 | } 122 | 123 | // NameNEQ applies the NEQ predicate on the "name" field. 124 | func NameNEQ(v string) predicate.TourProduct { 125 | return predicate.TourProduct(func(s *sql.Selector) { 126 | s.Where(sql.NEQ(s.C(FieldName), v)) 127 | }) 128 | } 129 | 130 | // NameIn applies the In predicate on the "name" field. 131 | func NameIn(vs ...string) predicate.TourProduct { 132 | v := make([]interface{}, len(vs)) 133 | for i := range v { 134 | v[i] = vs[i] 135 | } 136 | return predicate.TourProduct(func(s *sql.Selector) { 137 | // if not arguments were provided, append the FALSE constants, 138 | // since we can't apply "IN ()". This will make this predicate falsy. 139 | if len(v) == 0 { 140 | s.Where(sql.False()) 141 | return 142 | } 143 | s.Where(sql.In(s.C(FieldName), v...)) 144 | }) 145 | } 146 | 147 | // NameNotIn applies the NotIn predicate on the "name" field. 148 | func NameNotIn(vs ...string) predicate.TourProduct { 149 | v := make([]interface{}, len(vs)) 150 | for i := range v { 151 | v[i] = vs[i] 152 | } 153 | return predicate.TourProduct(func(s *sql.Selector) { 154 | // if not arguments were provided, append the FALSE constants, 155 | // since we can't apply "IN ()". This will make this predicate falsy. 156 | if len(v) == 0 { 157 | s.Where(sql.False()) 158 | return 159 | } 160 | s.Where(sql.NotIn(s.C(FieldName), v...)) 161 | }) 162 | } 163 | 164 | // NameGT applies the GT predicate on the "name" field. 165 | func NameGT(v string) predicate.TourProduct { 166 | return predicate.TourProduct(func(s *sql.Selector) { 167 | s.Where(sql.GT(s.C(FieldName), v)) 168 | }) 169 | } 170 | 171 | // NameGTE applies the GTE predicate on the "name" field. 172 | func NameGTE(v string) predicate.TourProduct { 173 | return predicate.TourProduct(func(s *sql.Selector) { 174 | s.Where(sql.GTE(s.C(FieldName), v)) 175 | }) 176 | } 177 | 178 | // NameLT applies the LT predicate on the "name" field. 179 | func NameLT(v string) predicate.TourProduct { 180 | return predicate.TourProduct(func(s *sql.Selector) { 181 | s.Where(sql.LT(s.C(FieldName), v)) 182 | }) 183 | } 184 | 185 | // NameLTE applies the LTE predicate on the "name" field. 186 | func NameLTE(v string) predicate.TourProduct { 187 | return predicate.TourProduct(func(s *sql.Selector) { 188 | s.Where(sql.LTE(s.C(FieldName), v)) 189 | }) 190 | } 191 | 192 | // NameContains applies the Contains predicate on the "name" field. 193 | func NameContains(v string) predicate.TourProduct { 194 | return predicate.TourProduct(func(s *sql.Selector) { 195 | s.Where(sql.Contains(s.C(FieldName), v)) 196 | }) 197 | } 198 | 199 | // NameHasPrefix applies the HasPrefix predicate on the "name" field. 200 | func NameHasPrefix(v string) predicate.TourProduct { 201 | return predicate.TourProduct(func(s *sql.Selector) { 202 | s.Where(sql.HasPrefix(s.C(FieldName), v)) 203 | }) 204 | } 205 | 206 | // NameHasSuffix applies the HasSuffix predicate on the "name" field. 207 | func NameHasSuffix(v string) predicate.TourProduct { 208 | return predicate.TourProduct(func(s *sql.Selector) { 209 | s.Where(sql.HasSuffix(s.C(FieldName), v)) 210 | }) 211 | } 212 | 213 | // NameEqualFold applies the EqualFold predicate on the "name" field. 214 | func NameEqualFold(v string) predicate.TourProduct { 215 | return predicate.TourProduct(func(s *sql.Selector) { 216 | s.Where(sql.EqualFold(s.C(FieldName), v)) 217 | }) 218 | } 219 | 220 | // NameContainsFold applies the ContainsFold predicate on the "name" field. 221 | func NameContainsFold(v string) predicate.TourProduct { 222 | return predicate.TourProduct(func(s *sql.Selector) { 223 | s.Where(sql.ContainsFold(s.C(FieldName), v)) 224 | }) 225 | } 226 | 227 | // PriceEQ applies the EQ predicate on the "price" field. 228 | func PriceEQ(v int) predicate.TourProduct { 229 | return predicate.TourProduct(func(s *sql.Selector) { 230 | s.Where(sql.EQ(s.C(FieldPrice), v)) 231 | }) 232 | } 233 | 234 | // PriceNEQ applies the NEQ predicate on the "price" field. 235 | func PriceNEQ(v int) predicate.TourProduct { 236 | return predicate.TourProduct(func(s *sql.Selector) { 237 | s.Where(sql.NEQ(s.C(FieldPrice), v)) 238 | }) 239 | } 240 | 241 | // PriceIn applies the In predicate on the "price" field. 242 | func PriceIn(vs ...int) predicate.TourProduct { 243 | v := make([]interface{}, len(vs)) 244 | for i := range v { 245 | v[i] = vs[i] 246 | } 247 | return predicate.TourProduct(func(s *sql.Selector) { 248 | // if not arguments were provided, append the FALSE constants, 249 | // since we can't apply "IN ()". This will make this predicate falsy. 250 | if len(v) == 0 { 251 | s.Where(sql.False()) 252 | return 253 | } 254 | s.Where(sql.In(s.C(FieldPrice), v...)) 255 | }) 256 | } 257 | 258 | // PriceNotIn applies the NotIn predicate on the "price" field. 259 | func PriceNotIn(vs ...int) predicate.TourProduct { 260 | v := make([]interface{}, len(vs)) 261 | for i := range v { 262 | v[i] = vs[i] 263 | } 264 | return predicate.TourProduct(func(s *sql.Selector) { 265 | // if not arguments were provided, append the FALSE constants, 266 | // since we can't apply "IN ()". This will make this predicate falsy. 267 | if len(v) == 0 { 268 | s.Where(sql.False()) 269 | return 270 | } 271 | s.Where(sql.NotIn(s.C(FieldPrice), v...)) 272 | }) 273 | } 274 | 275 | // PriceGT applies the GT predicate on the "price" field. 276 | func PriceGT(v int) predicate.TourProduct { 277 | return predicate.TourProduct(func(s *sql.Selector) { 278 | s.Where(sql.GT(s.C(FieldPrice), v)) 279 | }) 280 | } 281 | 282 | // PriceGTE applies the GTE predicate on the "price" field. 283 | func PriceGTE(v int) predicate.TourProduct { 284 | return predicate.TourProduct(func(s *sql.Selector) { 285 | s.Where(sql.GTE(s.C(FieldPrice), v)) 286 | }) 287 | } 288 | 289 | // PriceLT applies the LT predicate on the "price" field. 290 | func PriceLT(v int) predicate.TourProduct { 291 | return predicate.TourProduct(func(s *sql.Selector) { 292 | s.Where(sql.LT(s.C(FieldPrice), v)) 293 | }) 294 | } 295 | 296 | // PriceLTE applies the LTE predicate on the "price" field. 297 | func PriceLTE(v int) predicate.TourProduct { 298 | return predicate.TourProduct(func(s *sql.Selector) { 299 | s.Where(sql.LTE(s.C(FieldPrice), v)) 300 | }) 301 | } 302 | 303 | // ForSaleEQ applies the EQ predicate on the "forSale" field. 304 | func ForSaleEQ(v bool) predicate.TourProduct { 305 | return predicate.TourProduct(func(s *sql.Selector) { 306 | s.Where(sql.EQ(s.C(FieldForSale), v)) 307 | }) 308 | } 309 | 310 | // ForSaleNEQ applies the NEQ predicate on the "forSale" field. 311 | func ForSaleNEQ(v bool) predicate.TourProduct { 312 | return predicate.TourProduct(func(s *sql.Selector) { 313 | s.Where(sql.NEQ(s.C(FieldForSale), v)) 314 | }) 315 | } 316 | 317 | // HasManager applies the HasEdge predicate on the "manager" edge. 318 | func HasManager() predicate.TourProduct { 319 | return predicate.TourProduct(func(s *sql.Selector) { 320 | step := sqlgraph.NewStep( 321 | sqlgraph.From(Table, FieldID), 322 | sqlgraph.To(ManagerTable, FieldID), 323 | sqlgraph.Edge(sqlgraph.M2O, true, ManagerTable, ManagerColumn), 324 | ) 325 | sqlgraph.HasNeighbors(s, step) 326 | }) 327 | } 328 | 329 | // HasManagerWith applies the HasEdge predicate on the "manager" edge with a given conditions (other predicates). 330 | func HasManagerWith(preds ...predicate.User) predicate.TourProduct { 331 | return predicate.TourProduct(func(s *sql.Selector) { 332 | step := sqlgraph.NewStep( 333 | sqlgraph.From(Table, FieldID), 334 | sqlgraph.To(ManagerInverseTable, FieldID), 335 | sqlgraph.Edge(sqlgraph.M2O, true, ManagerTable, ManagerColumn), 336 | ) 337 | sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { 338 | for _, p := range preds { 339 | p(s) 340 | } 341 | }) 342 | }) 343 | } 344 | 345 | // And groups predicates with the AND operator between them. 346 | func And(predicates ...predicate.TourProduct) predicate.TourProduct { 347 | return predicate.TourProduct(func(s *sql.Selector) { 348 | s1 := s.Clone().SetP(nil) 349 | for _, p := range predicates { 350 | p(s1) 351 | } 352 | s.Where(s1.P()) 353 | }) 354 | } 355 | 356 | // Or groups predicates with the OR operator between them. 357 | func Or(predicates ...predicate.TourProduct) predicate.TourProduct { 358 | return predicate.TourProduct(func(s *sql.Selector) { 359 | s1 := s.Clone().SetP(nil) 360 | for i, p := range predicates { 361 | if i > 0 { 362 | s1.Or() 363 | } 364 | p(s1) 365 | } 366 | s.Where(s1.P()) 367 | }) 368 | } 369 | 370 | // Not applies the not operator on the given predicate. 371 | func Not(p predicate.TourProduct) predicate.TourProduct { 372 | return predicate.TourProduct(func(s *sql.Selector) { 373 | p(s.Not()) 374 | }) 375 | } 376 | -------------------------------------------------------------------------------- /db/ent/tourproduct_create.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | "db/ent/tourproduct" 8 | "db/ent/user" 9 | "errors" 10 | "fmt" 11 | 12 | "entgo.io/ent/dialect/sql/sqlgraph" 13 | "entgo.io/ent/schema/field" 14 | ) 15 | 16 | // TourProductCreate is the builder for creating a TourProduct entity. 17 | type TourProductCreate struct { 18 | config 19 | mutation *TourProductMutation 20 | hooks []Hook 21 | } 22 | 23 | // SetName sets the "name" field. 24 | func (tpc *TourProductCreate) SetName(s string) *TourProductCreate { 25 | tpc.mutation.SetName(s) 26 | return tpc 27 | } 28 | 29 | // SetPrice sets the "price" field. 30 | func (tpc *TourProductCreate) SetPrice(i int) *TourProductCreate { 31 | tpc.mutation.SetPrice(i) 32 | return tpc 33 | } 34 | 35 | // SetForSale sets the "forSale" field. 36 | func (tpc *TourProductCreate) SetForSale(b bool) *TourProductCreate { 37 | tpc.mutation.SetForSale(b) 38 | return tpc 39 | } 40 | 41 | // SetNillableForSale sets the "forSale" field if the given value is not nil. 42 | func (tpc *TourProductCreate) SetNillableForSale(b *bool) *TourProductCreate { 43 | if b != nil { 44 | tpc.SetForSale(*b) 45 | } 46 | return tpc 47 | } 48 | 49 | // SetManagerID sets the "manager" edge to the User entity by ID. 50 | func (tpc *TourProductCreate) SetManagerID(id string) *TourProductCreate { 51 | tpc.mutation.SetManagerID(id) 52 | return tpc 53 | } 54 | 55 | // SetManager sets the "manager" edge to the User entity. 56 | func (tpc *TourProductCreate) SetManager(u *User) *TourProductCreate { 57 | return tpc.SetManagerID(u.ID) 58 | } 59 | 60 | // Mutation returns the TourProductMutation object of the builder. 61 | func (tpc *TourProductCreate) Mutation() *TourProductMutation { 62 | return tpc.mutation 63 | } 64 | 65 | // Save creates the TourProduct in the database. 66 | func (tpc *TourProductCreate) Save(ctx context.Context) (*TourProduct, error) { 67 | var ( 68 | err error 69 | node *TourProduct 70 | ) 71 | tpc.defaults() 72 | if len(tpc.hooks) == 0 { 73 | if err = tpc.check(); err != nil { 74 | return nil, err 75 | } 76 | node, err = tpc.sqlSave(ctx) 77 | } else { 78 | var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { 79 | mutation, ok := m.(*TourProductMutation) 80 | if !ok { 81 | return nil, fmt.Errorf("unexpected mutation type %T", m) 82 | } 83 | if err = tpc.check(); err != nil { 84 | return nil, err 85 | } 86 | tpc.mutation = mutation 87 | node, err = tpc.sqlSave(ctx) 88 | mutation.done = true 89 | return node, err 90 | }) 91 | for i := len(tpc.hooks) - 1; i >= 0; i-- { 92 | mut = tpc.hooks[i](mut) 93 | } 94 | if _, err := mut.Mutate(ctx, tpc.mutation); err != nil { 95 | return nil, err 96 | } 97 | } 98 | return node, err 99 | } 100 | 101 | // SaveX calls Save and panics if Save returns an error. 102 | func (tpc *TourProductCreate) SaveX(ctx context.Context) *TourProduct { 103 | v, err := tpc.Save(ctx) 104 | if err != nil { 105 | panic(err) 106 | } 107 | return v 108 | } 109 | 110 | // defaults sets the default values of the builder before save. 111 | func (tpc *TourProductCreate) defaults() { 112 | if _, ok := tpc.mutation.ForSale(); !ok { 113 | v := tourproduct.DefaultForSale 114 | tpc.mutation.SetForSale(v) 115 | } 116 | } 117 | 118 | // check runs all checks and user-defined validators on the builder. 119 | func (tpc *TourProductCreate) check() error { 120 | if _, ok := tpc.mutation.Name(); !ok { 121 | return &ValidationError{Name: "name", err: errors.New("ent: missing required field \"name\"")} 122 | } 123 | if _, ok := tpc.mutation.Price(); !ok { 124 | return &ValidationError{Name: "price", err: errors.New("ent: missing required field \"price\"")} 125 | } 126 | if _, ok := tpc.mutation.ForSale(); !ok { 127 | return &ValidationError{Name: "forSale", err: errors.New("ent: missing required field \"forSale\"")} 128 | } 129 | if _, ok := tpc.mutation.ManagerID(); !ok { 130 | return &ValidationError{Name: "manager", err: errors.New("ent: missing required edge \"manager\"")} 131 | } 132 | return nil 133 | } 134 | 135 | func (tpc *TourProductCreate) sqlSave(ctx context.Context) (*TourProduct, error) { 136 | _node, _spec := tpc.createSpec() 137 | if err := sqlgraph.CreateNode(ctx, tpc.driver, _spec); err != nil { 138 | if cerr, ok := isSQLConstraintError(err); ok { 139 | err = cerr 140 | } 141 | return nil, err 142 | } 143 | id := _spec.ID.Value.(int64) 144 | _node.ID = int(id) 145 | return _node, nil 146 | } 147 | 148 | func (tpc *TourProductCreate) createSpec() (*TourProduct, *sqlgraph.CreateSpec) { 149 | var ( 150 | _node = &TourProduct{config: tpc.config} 151 | _spec = &sqlgraph.CreateSpec{ 152 | Table: tourproduct.Table, 153 | ID: &sqlgraph.FieldSpec{ 154 | Type: field.TypeInt, 155 | Column: tourproduct.FieldID, 156 | }, 157 | } 158 | ) 159 | if value, ok := tpc.mutation.Name(); ok { 160 | _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ 161 | Type: field.TypeString, 162 | Value: value, 163 | Column: tourproduct.FieldName, 164 | }) 165 | _node.Name = value 166 | } 167 | if value, ok := tpc.mutation.Price(); ok { 168 | _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ 169 | Type: field.TypeInt, 170 | Value: value, 171 | Column: tourproduct.FieldPrice, 172 | }) 173 | _node.Price = value 174 | } 175 | if value, ok := tpc.mutation.ForSale(); ok { 176 | _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ 177 | Type: field.TypeBool, 178 | Value: value, 179 | Column: tourproduct.FieldForSale, 180 | }) 181 | _node.ForSale = value 182 | } 183 | if nodes := tpc.mutation.ManagerIDs(); len(nodes) > 0 { 184 | edge := &sqlgraph.EdgeSpec{ 185 | Rel: sqlgraph.M2O, 186 | Inverse: true, 187 | Table: tourproduct.ManagerTable, 188 | Columns: []string{tourproduct.ManagerColumn}, 189 | Bidi: false, 190 | Target: &sqlgraph.EdgeTarget{ 191 | IDSpec: &sqlgraph.FieldSpec{ 192 | Type: field.TypeString, 193 | Column: user.FieldID, 194 | }, 195 | }, 196 | } 197 | for _, k := range nodes { 198 | edge.Target.Nodes = append(edge.Target.Nodes, k) 199 | } 200 | _node.user_products = &nodes[0] 201 | _spec.Edges = append(_spec.Edges, edge) 202 | } 203 | return _node, _spec 204 | } 205 | 206 | // TourProductCreateBulk is the builder for creating many TourProduct entities in bulk. 207 | type TourProductCreateBulk struct { 208 | config 209 | builders []*TourProductCreate 210 | } 211 | 212 | // Save creates the TourProduct entities in the database. 213 | func (tpcb *TourProductCreateBulk) Save(ctx context.Context) ([]*TourProduct, error) { 214 | specs := make([]*sqlgraph.CreateSpec, len(tpcb.builders)) 215 | nodes := make([]*TourProduct, len(tpcb.builders)) 216 | mutators := make([]Mutator, len(tpcb.builders)) 217 | for i := range tpcb.builders { 218 | func(i int, root context.Context) { 219 | builder := tpcb.builders[i] 220 | builder.defaults() 221 | var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { 222 | mutation, ok := m.(*TourProductMutation) 223 | if !ok { 224 | return nil, fmt.Errorf("unexpected mutation type %T", m) 225 | } 226 | if err := builder.check(); err != nil { 227 | return nil, err 228 | } 229 | builder.mutation = mutation 230 | nodes[i], specs[i] = builder.createSpec() 231 | var err error 232 | if i < len(mutators)-1 { 233 | _, err = mutators[i+1].Mutate(root, tpcb.builders[i+1].mutation) 234 | } else { 235 | // Invoke the actual operation on the latest mutation in the chain. 236 | if err = sqlgraph.BatchCreate(ctx, tpcb.driver, &sqlgraph.BatchCreateSpec{Nodes: specs}); err != nil { 237 | if cerr, ok := isSQLConstraintError(err); ok { 238 | err = cerr 239 | } 240 | } 241 | } 242 | mutation.done = true 243 | if err != nil { 244 | return nil, err 245 | } 246 | id := specs[i].ID.Value.(int64) 247 | nodes[i].ID = int(id) 248 | return nodes[i], nil 249 | }) 250 | for i := len(builder.hooks) - 1; i >= 0; i-- { 251 | mut = builder.hooks[i](mut) 252 | } 253 | mutators[i] = mut 254 | }(i, ctx) 255 | } 256 | if len(mutators) > 0 { 257 | if _, err := mutators[0].Mutate(ctx, tpcb.builders[0].mutation); err != nil { 258 | return nil, err 259 | } 260 | } 261 | return nodes, nil 262 | } 263 | 264 | // SaveX is like Save, but panics if an error occurs. 265 | func (tpcb *TourProductCreateBulk) SaveX(ctx context.Context) []*TourProduct { 266 | v, err := tpcb.Save(ctx) 267 | if err != nil { 268 | panic(err) 269 | } 270 | return v 271 | } 272 | -------------------------------------------------------------------------------- /db/ent/tourproduct_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | "db/ent/predicate" 8 | "db/ent/tourproduct" 9 | "fmt" 10 | 11 | "entgo.io/ent/dialect/sql" 12 | "entgo.io/ent/dialect/sql/sqlgraph" 13 | "entgo.io/ent/schema/field" 14 | ) 15 | 16 | // TourProductDelete is the builder for deleting a TourProduct entity. 17 | type TourProductDelete struct { 18 | config 19 | hooks []Hook 20 | mutation *TourProductMutation 21 | } 22 | 23 | // Where adds a new predicate to the TourProductDelete builder. 24 | func (tpd *TourProductDelete) Where(ps ...predicate.TourProduct) *TourProductDelete { 25 | tpd.mutation.predicates = append(tpd.mutation.predicates, ps...) 26 | return tpd 27 | } 28 | 29 | // Exec executes the deletion query and returns how many vertices were deleted. 30 | func (tpd *TourProductDelete) Exec(ctx context.Context) (int, error) { 31 | var ( 32 | err error 33 | affected int 34 | ) 35 | if len(tpd.hooks) == 0 { 36 | affected, err = tpd.sqlExec(ctx) 37 | } else { 38 | var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { 39 | mutation, ok := m.(*TourProductMutation) 40 | if !ok { 41 | return nil, fmt.Errorf("unexpected mutation type %T", m) 42 | } 43 | tpd.mutation = mutation 44 | affected, err = tpd.sqlExec(ctx) 45 | mutation.done = true 46 | return affected, err 47 | }) 48 | for i := len(tpd.hooks) - 1; i >= 0; i-- { 49 | mut = tpd.hooks[i](mut) 50 | } 51 | if _, err := mut.Mutate(ctx, tpd.mutation); err != nil { 52 | return 0, err 53 | } 54 | } 55 | return affected, err 56 | } 57 | 58 | // ExecX is like Exec, but panics if an error occurs. 59 | func (tpd *TourProductDelete) ExecX(ctx context.Context) int { 60 | n, err := tpd.Exec(ctx) 61 | if err != nil { 62 | panic(err) 63 | } 64 | return n 65 | } 66 | 67 | func (tpd *TourProductDelete) sqlExec(ctx context.Context) (int, error) { 68 | _spec := &sqlgraph.DeleteSpec{ 69 | Node: &sqlgraph.NodeSpec{ 70 | Table: tourproduct.Table, 71 | ID: &sqlgraph.FieldSpec{ 72 | Type: field.TypeInt, 73 | Column: tourproduct.FieldID, 74 | }, 75 | }, 76 | } 77 | if ps := tpd.mutation.predicates; len(ps) > 0 { 78 | _spec.Predicate = func(selector *sql.Selector) { 79 | for i := range ps { 80 | ps[i](selector) 81 | } 82 | } 83 | } 84 | return sqlgraph.DeleteNodes(ctx, tpd.driver, _spec) 85 | } 86 | 87 | // TourProductDeleteOne is the builder for deleting a single TourProduct entity. 88 | type TourProductDeleteOne struct { 89 | tpd *TourProductDelete 90 | } 91 | 92 | // Exec executes the deletion query. 93 | func (tpdo *TourProductDeleteOne) Exec(ctx context.Context) error { 94 | n, err := tpdo.tpd.Exec(ctx) 95 | switch { 96 | case err != nil: 97 | return err 98 | case n == 0: 99 | return &NotFoundError{tourproduct.Label} 100 | default: 101 | return nil 102 | } 103 | } 104 | 105 | // ExecX is like Exec, but panics if an error occurs. 106 | func (tpdo *TourProductDeleteOne) ExecX(ctx context.Context) { 107 | tpdo.tpd.ExecX(ctx) 108 | } 109 | -------------------------------------------------------------------------------- /db/ent/tx.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | "sync" 8 | 9 | "entgo.io/ent/dialect" 10 | ) 11 | 12 | // Tx is a transactional client that is created by calling Client.Tx(). 13 | type Tx struct { 14 | config 15 | // TourProduct is the client for interacting with the TourProduct builders. 16 | TourProduct *TourProductClient 17 | // User is the client for interacting with the User builders. 18 | User *UserClient 19 | 20 | // lazily loaded. 21 | client *Client 22 | clientOnce sync.Once 23 | 24 | // completion callbacks. 25 | mu sync.Mutex 26 | onCommit []CommitHook 27 | onRollback []RollbackHook 28 | 29 | // ctx lives for the life of the transaction. It is 30 | // the same context used by the underlying connection. 31 | ctx context.Context 32 | } 33 | 34 | type ( 35 | // Committer is the interface that wraps the Committer method. 36 | Committer interface { 37 | Commit(context.Context, *Tx) error 38 | } 39 | 40 | // The CommitFunc type is an adapter to allow the use of ordinary 41 | // function as a Committer. If f is a function with the appropriate 42 | // signature, CommitFunc(f) is a Committer that calls f. 43 | CommitFunc func(context.Context, *Tx) error 44 | 45 | // CommitHook defines the "commit middleware". A function that gets a Committer 46 | // and returns a Committer. For example: 47 | // 48 | // hook := func(next ent.Committer) ent.Committer { 49 | // return ent.CommitFunc(func(context.Context, tx *ent.Tx) error { 50 | // // Do some stuff before. 51 | // if err := next.Commit(ctx, tx); err != nil { 52 | // return err 53 | // } 54 | // // Do some stuff after. 55 | // return nil 56 | // }) 57 | // } 58 | // 59 | CommitHook func(Committer) Committer 60 | ) 61 | 62 | // Commit calls f(ctx, m). 63 | func (f CommitFunc) Commit(ctx context.Context, tx *Tx) error { 64 | return f(ctx, tx) 65 | } 66 | 67 | // Commit commits the transaction. 68 | func (tx *Tx) Commit() error { 69 | txDriver := tx.config.driver.(*txDriver) 70 | var fn Committer = CommitFunc(func(context.Context, *Tx) error { 71 | return txDriver.tx.Commit() 72 | }) 73 | tx.mu.Lock() 74 | hooks := append([]CommitHook(nil), tx.onCommit...) 75 | tx.mu.Unlock() 76 | for i := len(hooks) - 1; i >= 0; i-- { 77 | fn = hooks[i](fn) 78 | } 79 | return fn.Commit(tx.ctx, tx) 80 | } 81 | 82 | // OnCommit adds a hook to call on commit. 83 | func (tx *Tx) OnCommit(f CommitHook) { 84 | tx.mu.Lock() 85 | defer tx.mu.Unlock() 86 | tx.onCommit = append(tx.onCommit, f) 87 | } 88 | 89 | type ( 90 | // Rollbacker is the interface that wraps the Rollbacker method. 91 | Rollbacker interface { 92 | Rollback(context.Context, *Tx) error 93 | } 94 | 95 | // The RollbackFunc type is an adapter to allow the use of ordinary 96 | // function as a Rollbacker. If f is a function with the appropriate 97 | // signature, RollbackFunc(f) is a Rollbacker that calls f. 98 | RollbackFunc func(context.Context, *Tx) error 99 | 100 | // RollbackHook defines the "rollback middleware". A function that gets a Rollbacker 101 | // and returns a Rollbacker. For example: 102 | // 103 | // hook := func(next ent.Rollbacker) ent.Rollbacker { 104 | // return ent.RollbackFunc(func(context.Context, tx *ent.Tx) error { 105 | // // Do some stuff before. 106 | // if err := next.Rollback(ctx, tx); err != nil { 107 | // return err 108 | // } 109 | // // Do some stuff after. 110 | // return nil 111 | // }) 112 | // } 113 | // 114 | RollbackHook func(Rollbacker) Rollbacker 115 | ) 116 | 117 | // Rollback calls f(ctx, m). 118 | func (f RollbackFunc) Rollback(ctx context.Context, tx *Tx) error { 119 | return f(ctx, tx) 120 | } 121 | 122 | // Rollback rollbacks the transaction. 123 | func (tx *Tx) Rollback() error { 124 | txDriver := tx.config.driver.(*txDriver) 125 | var fn Rollbacker = RollbackFunc(func(context.Context, *Tx) error { 126 | return txDriver.tx.Rollback() 127 | }) 128 | tx.mu.Lock() 129 | hooks := append([]RollbackHook(nil), tx.onRollback...) 130 | tx.mu.Unlock() 131 | for i := len(hooks) - 1; i >= 0; i-- { 132 | fn = hooks[i](fn) 133 | } 134 | return fn.Rollback(tx.ctx, tx) 135 | } 136 | 137 | // OnRollback adds a hook to call on rollback. 138 | func (tx *Tx) OnRollback(f RollbackHook) { 139 | tx.mu.Lock() 140 | defer tx.mu.Unlock() 141 | tx.onRollback = append(tx.onRollback, f) 142 | } 143 | 144 | // Client returns a Client that binds to current transaction. 145 | func (tx *Tx) Client() *Client { 146 | tx.clientOnce.Do(func() { 147 | tx.client = &Client{config: tx.config} 148 | tx.client.init() 149 | }) 150 | return tx.client 151 | } 152 | 153 | func (tx *Tx) init() { 154 | tx.TourProduct = NewTourProductClient(tx.config) 155 | tx.User = NewUserClient(tx.config) 156 | } 157 | 158 | // txDriver wraps the given dialect.Tx with a nop dialect.Driver implementation. 159 | // The idea is to support transactions without adding any extra code to the builders. 160 | // When a builder calls to driver.Tx(), it gets the same dialect.Tx instance. 161 | // Commit and Rollback are nop for the internal builders and the user must call one 162 | // of them in order to commit or rollback the transaction. 163 | // 164 | // If a closed transaction is embedded in one of the generated entities, and the entity 165 | // applies a query, for example: TourProduct.QueryXXX(), the query will be executed 166 | // through the driver which created this transaction. 167 | // 168 | // Note that txDriver is not goroutine safe. 169 | type txDriver struct { 170 | // the driver we started the transaction from. 171 | drv dialect.Driver 172 | // tx is the underlying transaction. 173 | tx dialect.Tx 174 | } 175 | 176 | // newTx creates a new transactional driver. 177 | func newTx(ctx context.Context, drv dialect.Driver) (*txDriver, error) { 178 | tx, err := drv.Tx(ctx) 179 | if err != nil { 180 | return nil, err 181 | } 182 | return &txDriver{tx: tx, drv: drv}, nil 183 | } 184 | 185 | // Tx returns the transaction wrapper (txDriver) to avoid Commit or Rollback calls 186 | // from the internal builders. Should be called only by the internal builders. 187 | func (tx *txDriver) Tx(context.Context) (dialect.Tx, error) { return tx, nil } 188 | 189 | // Dialect returns the dialect of the driver we started the transaction from. 190 | func (tx *txDriver) Dialect() string { return tx.drv.Dialect() } 191 | 192 | // Close is a nop close. 193 | func (*txDriver) Close() error { return nil } 194 | 195 | // Commit is a nop commit for the internal builders. 196 | // User must call `Tx.Commit` in order to commit the transaction. 197 | func (*txDriver) Commit() error { return nil } 198 | 199 | // Rollback is a nop rollback for the internal builders. 200 | // User must call `Tx.Rollback` in order to rollback the transaction. 201 | func (*txDriver) Rollback() error { return nil } 202 | 203 | // Exec calls tx.Exec. 204 | func (tx *txDriver) Exec(ctx context.Context, query string, args, v interface{}) error { 205 | return tx.tx.Exec(ctx, query, args, v) 206 | } 207 | 208 | // Query calls tx.Query. 209 | func (tx *txDriver) Query(ctx context.Context, query string, args, v interface{}) error { 210 | return tx.tx.Query(ctx, query, args, v) 211 | } 212 | 213 | var _ dialect.Driver = (*txDriver)(nil) 214 | -------------------------------------------------------------------------------- /db/ent/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "db/ent/user" 7 | "fmt" 8 | "strings" 9 | 10 | "entgo.io/ent/dialect/sql" 11 | ) 12 | 13 | // User is the model entity for the User schema. 14 | type User struct { 15 | config `json:"-"` 16 | // ID of the ent. 17 | ID string `json:"id,omitempty"` 18 | // Name holds the value of the "name" field. 19 | Name string `json:"name,omitempty"` 20 | // IsActivated holds the value of the "isActivated" field. 21 | IsActivated bool `json:"isActivated,omitempty"` 22 | // Edges holds the relations/edges for other nodes in the graph. 23 | // The values are being populated by the UserQuery when eager-loading is set. 24 | Edges UserEdges `json:"edges"` 25 | } 26 | 27 | // UserEdges holds the relations/edges for other nodes in the graph. 28 | type UserEdges struct { 29 | // Products holds the value of the products edge. 30 | Products []*TourProduct `json:"products,omitempty"` 31 | // loadedTypes holds the information for reporting if a 32 | // type was loaded (or requested) in eager-loading or not. 33 | loadedTypes [1]bool 34 | } 35 | 36 | // ProductsOrErr returns the Products value or an error if the edge 37 | // was not loaded in eager-loading. 38 | func (e UserEdges) ProductsOrErr() ([]*TourProduct, error) { 39 | if e.loadedTypes[0] { 40 | return e.Products, nil 41 | } 42 | return nil, &NotLoadedError{edge: "products"} 43 | } 44 | 45 | // scanValues returns the types for scanning values from sql.Rows. 46 | func (*User) scanValues(columns []string) ([]interface{}, error) { 47 | values := make([]interface{}, len(columns)) 48 | for i := range columns { 49 | switch columns[i] { 50 | case user.FieldIsActivated: 51 | values[i] = new(sql.NullBool) 52 | case user.FieldID, user.FieldName: 53 | values[i] = new(sql.NullString) 54 | default: 55 | return nil, fmt.Errorf("unexpected column %q for type User", columns[i]) 56 | } 57 | } 58 | return values, nil 59 | } 60 | 61 | // assignValues assigns the values that were returned from sql.Rows (after scanning) 62 | // to the User fields. 63 | func (u *User) assignValues(columns []string, values []interface{}) error { 64 | if m, n := len(values), len(columns); m < n { 65 | return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) 66 | } 67 | for i := range columns { 68 | switch columns[i] { 69 | case user.FieldID: 70 | if value, ok := values[i].(*sql.NullString); !ok { 71 | return fmt.Errorf("unexpected type %T for field id", values[i]) 72 | } else if value.Valid { 73 | u.ID = value.String 74 | } 75 | case user.FieldName: 76 | if value, ok := values[i].(*sql.NullString); !ok { 77 | return fmt.Errorf("unexpected type %T for field name", values[i]) 78 | } else if value.Valid { 79 | u.Name = value.String 80 | } 81 | case user.FieldIsActivated: 82 | if value, ok := values[i].(*sql.NullBool); !ok { 83 | return fmt.Errorf("unexpected type %T for field isActivated", values[i]) 84 | } else if value.Valid { 85 | u.IsActivated = value.Bool 86 | } 87 | } 88 | } 89 | return nil 90 | } 91 | 92 | // QueryProducts queries the "products" edge of the User entity. 93 | func (u *User) QueryProducts() *TourProductQuery { 94 | return (&UserClient{config: u.config}).QueryProducts(u) 95 | } 96 | 97 | // Update returns a builder for updating this User. 98 | // Note that you need to call User.Unwrap() before calling this method if this User 99 | // was returned from a transaction, and the transaction was committed or rolled back. 100 | func (u *User) Update() *UserUpdateOne { 101 | return (&UserClient{config: u.config}).UpdateOne(u) 102 | } 103 | 104 | // Unwrap unwraps the User entity that was returned from a transaction after it was closed, 105 | // so that all future queries will be executed through the driver which created the transaction. 106 | func (u *User) Unwrap() *User { 107 | tx, ok := u.config.driver.(*txDriver) 108 | if !ok { 109 | panic("ent: User is not a transactional entity") 110 | } 111 | u.config.driver = tx.drv 112 | return u 113 | } 114 | 115 | // String implements the fmt.Stringer. 116 | func (u *User) String() string { 117 | var builder strings.Builder 118 | builder.WriteString("User(") 119 | builder.WriteString(fmt.Sprintf("id=%v", u.ID)) 120 | builder.WriteString(", name=") 121 | builder.WriteString(u.Name) 122 | builder.WriteString(", isActivated=") 123 | builder.WriteString(fmt.Sprintf("%v", u.IsActivated)) 124 | builder.WriteByte(')') 125 | return builder.String() 126 | } 127 | 128 | // Users is a parsable slice of User. 129 | type Users []*User 130 | 131 | func (u Users) config(cfg config) { 132 | for _i := range u { 133 | u[_i].config = cfg 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /db/ent/user/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package user 4 | 5 | const ( 6 | // Label holds the string label denoting the user type in the database. 7 | Label = "user" 8 | // FieldID holds the string denoting the id field in the database. 9 | FieldID = "id" 10 | // FieldName holds the string denoting the name field in the database. 11 | FieldName = "name" 12 | // FieldIsActivated holds the string denoting the isactivated field in the database. 13 | FieldIsActivated = "is_activated" 14 | // EdgeProducts holds the string denoting the products edge name in mutations. 15 | EdgeProducts = "products" 16 | // Table holds the table name of the user in the database. 17 | Table = "users" 18 | // ProductsTable is the table the holds the products relation/edge. 19 | ProductsTable = "tour_products" 20 | // ProductsInverseTable is the table name for the TourProduct entity. 21 | // It exists in this package in order to avoid circular dependency with the "tourproduct" package. 22 | ProductsInverseTable = "tour_products" 23 | // ProductsColumn is the table column denoting the products relation/edge. 24 | ProductsColumn = "user_products" 25 | ) 26 | 27 | // Columns holds all SQL columns for user fields. 28 | var Columns = []string{ 29 | FieldID, 30 | FieldName, 31 | FieldIsActivated, 32 | } 33 | 34 | // ValidColumn reports if the column name is valid (part of the table columns). 35 | func ValidColumn(column string) bool { 36 | for i := range Columns { 37 | if column == Columns[i] { 38 | return true 39 | } 40 | } 41 | return false 42 | } 43 | 44 | var ( 45 | // DefaultIsActivated holds the default value on creation for the "isActivated" field. 46 | DefaultIsActivated bool 47 | ) 48 | -------------------------------------------------------------------------------- /db/ent/user/where.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package user 4 | 5 | import ( 6 | "db/ent/predicate" 7 | 8 | "entgo.io/ent/dialect/sql" 9 | "entgo.io/ent/dialect/sql/sqlgraph" 10 | ) 11 | 12 | // ID filters vertices based on their ID field. 13 | func ID(id string) predicate.User { 14 | return predicate.User(func(s *sql.Selector) { 15 | s.Where(sql.EQ(s.C(FieldID), id)) 16 | }) 17 | } 18 | 19 | // IDEQ applies the EQ predicate on the ID field. 20 | func IDEQ(id string) predicate.User { 21 | return predicate.User(func(s *sql.Selector) { 22 | s.Where(sql.EQ(s.C(FieldID), id)) 23 | }) 24 | } 25 | 26 | // IDNEQ applies the NEQ predicate on the ID field. 27 | func IDNEQ(id string) predicate.User { 28 | return predicate.User(func(s *sql.Selector) { 29 | s.Where(sql.NEQ(s.C(FieldID), id)) 30 | }) 31 | } 32 | 33 | // IDIn applies the In predicate on the ID field. 34 | func IDIn(ids ...string) predicate.User { 35 | return predicate.User(func(s *sql.Selector) { 36 | // if not arguments were provided, append the FALSE constants, 37 | // since we can't apply "IN ()". This will make this predicate falsy. 38 | if len(ids) == 0 { 39 | s.Where(sql.False()) 40 | return 41 | } 42 | v := make([]interface{}, len(ids)) 43 | for i := range v { 44 | v[i] = ids[i] 45 | } 46 | s.Where(sql.In(s.C(FieldID), v...)) 47 | }) 48 | } 49 | 50 | // IDNotIn applies the NotIn predicate on the ID field. 51 | func IDNotIn(ids ...string) predicate.User { 52 | return predicate.User(func(s *sql.Selector) { 53 | // if not arguments were provided, append the FALSE constants, 54 | // since we can't apply "IN ()". This will make this predicate falsy. 55 | if len(ids) == 0 { 56 | s.Where(sql.False()) 57 | return 58 | } 59 | v := make([]interface{}, len(ids)) 60 | for i := range v { 61 | v[i] = ids[i] 62 | } 63 | s.Where(sql.NotIn(s.C(FieldID), v...)) 64 | }) 65 | } 66 | 67 | // IDGT applies the GT predicate on the ID field. 68 | func IDGT(id string) predicate.User { 69 | return predicate.User(func(s *sql.Selector) { 70 | s.Where(sql.GT(s.C(FieldID), id)) 71 | }) 72 | } 73 | 74 | // IDGTE applies the GTE predicate on the ID field. 75 | func IDGTE(id string) predicate.User { 76 | return predicate.User(func(s *sql.Selector) { 77 | s.Where(sql.GTE(s.C(FieldID), id)) 78 | }) 79 | } 80 | 81 | // IDLT applies the LT predicate on the ID field. 82 | func IDLT(id string) predicate.User { 83 | return predicate.User(func(s *sql.Selector) { 84 | s.Where(sql.LT(s.C(FieldID), id)) 85 | }) 86 | } 87 | 88 | // IDLTE applies the LTE predicate on the ID field. 89 | func IDLTE(id string) predicate.User { 90 | return predicate.User(func(s *sql.Selector) { 91 | s.Where(sql.LTE(s.C(FieldID), id)) 92 | }) 93 | } 94 | 95 | // Name applies equality check predicate on the "name" field. It's identical to NameEQ. 96 | func Name(v string) predicate.User { 97 | return predicate.User(func(s *sql.Selector) { 98 | s.Where(sql.EQ(s.C(FieldName), v)) 99 | }) 100 | } 101 | 102 | // IsActivated applies equality check predicate on the "isActivated" field. It's identical to IsActivatedEQ. 103 | func IsActivated(v bool) predicate.User { 104 | return predicate.User(func(s *sql.Selector) { 105 | s.Where(sql.EQ(s.C(FieldIsActivated), v)) 106 | }) 107 | } 108 | 109 | // NameEQ applies the EQ predicate on the "name" field. 110 | func NameEQ(v string) predicate.User { 111 | return predicate.User(func(s *sql.Selector) { 112 | s.Where(sql.EQ(s.C(FieldName), v)) 113 | }) 114 | } 115 | 116 | // NameNEQ applies the NEQ predicate on the "name" field. 117 | func NameNEQ(v string) predicate.User { 118 | return predicate.User(func(s *sql.Selector) { 119 | s.Where(sql.NEQ(s.C(FieldName), v)) 120 | }) 121 | } 122 | 123 | // NameIn applies the In predicate on the "name" field. 124 | func NameIn(vs ...string) predicate.User { 125 | v := make([]interface{}, len(vs)) 126 | for i := range v { 127 | v[i] = vs[i] 128 | } 129 | return predicate.User(func(s *sql.Selector) { 130 | // if not arguments were provided, append the FALSE constants, 131 | // since we can't apply "IN ()". This will make this predicate falsy. 132 | if len(v) == 0 { 133 | s.Where(sql.False()) 134 | return 135 | } 136 | s.Where(sql.In(s.C(FieldName), v...)) 137 | }) 138 | } 139 | 140 | // NameNotIn applies the NotIn predicate on the "name" field. 141 | func NameNotIn(vs ...string) predicate.User { 142 | v := make([]interface{}, len(vs)) 143 | for i := range v { 144 | v[i] = vs[i] 145 | } 146 | return predicate.User(func(s *sql.Selector) { 147 | // if not arguments were provided, append the FALSE constants, 148 | // since we can't apply "IN ()". This will make this predicate falsy. 149 | if len(v) == 0 { 150 | s.Where(sql.False()) 151 | return 152 | } 153 | s.Where(sql.NotIn(s.C(FieldName), v...)) 154 | }) 155 | } 156 | 157 | // NameGT applies the GT predicate on the "name" field. 158 | func NameGT(v string) predicate.User { 159 | return predicate.User(func(s *sql.Selector) { 160 | s.Where(sql.GT(s.C(FieldName), v)) 161 | }) 162 | } 163 | 164 | // NameGTE applies the GTE predicate on the "name" field. 165 | func NameGTE(v string) predicate.User { 166 | return predicate.User(func(s *sql.Selector) { 167 | s.Where(sql.GTE(s.C(FieldName), v)) 168 | }) 169 | } 170 | 171 | // NameLT applies the LT predicate on the "name" field. 172 | func NameLT(v string) predicate.User { 173 | return predicate.User(func(s *sql.Selector) { 174 | s.Where(sql.LT(s.C(FieldName), v)) 175 | }) 176 | } 177 | 178 | // NameLTE applies the LTE predicate on the "name" field. 179 | func NameLTE(v string) predicate.User { 180 | return predicate.User(func(s *sql.Selector) { 181 | s.Where(sql.LTE(s.C(FieldName), v)) 182 | }) 183 | } 184 | 185 | // NameContains applies the Contains predicate on the "name" field. 186 | func NameContains(v string) predicate.User { 187 | return predicate.User(func(s *sql.Selector) { 188 | s.Where(sql.Contains(s.C(FieldName), v)) 189 | }) 190 | } 191 | 192 | // NameHasPrefix applies the HasPrefix predicate on the "name" field. 193 | func NameHasPrefix(v string) predicate.User { 194 | return predicate.User(func(s *sql.Selector) { 195 | s.Where(sql.HasPrefix(s.C(FieldName), v)) 196 | }) 197 | } 198 | 199 | // NameHasSuffix applies the HasSuffix predicate on the "name" field. 200 | func NameHasSuffix(v string) predicate.User { 201 | return predicate.User(func(s *sql.Selector) { 202 | s.Where(sql.HasSuffix(s.C(FieldName), v)) 203 | }) 204 | } 205 | 206 | // NameEqualFold applies the EqualFold predicate on the "name" field. 207 | func NameEqualFold(v string) predicate.User { 208 | return predicate.User(func(s *sql.Selector) { 209 | s.Where(sql.EqualFold(s.C(FieldName), v)) 210 | }) 211 | } 212 | 213 | // NameContainsFold applies the ContainsFold predicate on the "name" field. 214 | func NameContainsFold(v string) predicate.User { 215 | return predicate.User(func(s *sql.Selector) { 216 | s.Where(sql.ContainsFold(s.C(FieldName), v)) 217 | }) 218 | } 219 | 220 | // IsActivatedEQ applies the EQ predicate on the "isActivated" field. 221 | func IsActivatedEQ(v bool) predicate.User { 222 | return predicate.User(func(s *sql.Selector) { 223 | s.Where(sql.EQ(s.C(FieldIsActivated), v)) 224 | }) 225 | } 226 | 227 | // IsActivatedNEQ applies the NEQ predicate on the "isActivated" field. 228 | func IsActivatedNEQ(v bool) predicate.User { 229 | return predicate.User(func(s *sql.Selector) { 230 | s.Where(sql.NEQ(s.C(FieldIsActivated), v)) 231 | }) 232 | } 233 | 234 | // HasProducts applies the HasEdge predicate on the "products" edge. 235 | func HasProducts() predicate.User { 236 | return predicate.User(func(s *sql.Selector) { 237 | step := sqlgraph.NewStep( 238 | sqlgraph.From(Table, FieldID), 239 | sqlgraph.To(ProductsTable, FieldID), 240 | sqlgraph.Edge(sqlgraph.O2M, false, ProductsTable, ProductsColumn), 241 | ) 242 | sqlgraph.HasNeighbors(s, step) 243 | }) 244 | } 245 | 246 | // HasProductsWith applies the HasEdge predicate on the "products" edge with a given conditions (other predicates). 247 | func HasProductsWith(preds ...predicate.TourProduct) predicate.User { 248 | return predicate.User(func(s *sql.Selector) { 249 | step := sqlgraph.NewStep( 250 | sqlgraph.From(Table, FieldID), 251 | sqlgraph.To(ProductsInverseTable, FieldID), 252 | sqlgraph.Edge(sqlgraph.O2M, false, ProductsTable, ProductsColumn), 253 | ) 254 | sqlgraph.HasNeighborsWith(s, step, func(s *sql.Selector) { 255 | for _, p := range preds { 256 | p(s) 257 | } 258 | }) 259 | }) 260 | } 261 | 262 | // And groups predicates with the AND operator between them. 263 | func And(predicates ...predicate.User) predicate.User { 264 | return predicate.User(func(s *sql.Selector) { 265 | s1 := s.Clone().SetP(nil) 266 | for _, p := range predicates { 267 | p(s1) 268 | } 269 | s.Where(s1.P()) 270 | }) 271 | } 272 | 273 | // Or groups predicates with the OR operator between them. 274 | func Or(predicates ...predicate.User) predicate.User { 275 | return predicate.User(func(s *sql.Selector) { 276 | s1 := s.Clone().SetP(nil) 277 | for i, p := range predicates { 278 | if i > 0 { 279 | s1.Or() 280 | } 281 | p(s1) 282 | } 283 | s.Where(s1.P()) 284 | }) 285 | } 286 | 287 | // Not applies the not operator on the given predicate. 288 | func Not(p predicate.User) predicate.User { 289 | return predicate.User(func(s *sql.Selector) { 290 | p(s.Not()) 291 | }) 292 | } 293 | -------------------------------------------------------------------------------- /db/ent/user_create.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | "db/ent/tourproduct" 8 | "db/ent/user" 9 | "errors" 10 | "fmt" 11 | 12 | "entgo.io/ent/dialect/sql/sqlgraph" 13 | "entgo.io/ent/schema/field" 14 | ) 15 | 16 | // UserCreate is the builder for creating a User entity. 17 | type UserCreate struct { 18 | config 19 | mutation *UserMutation 20 | hooks []Hook 21 | } 22 | 23 | // SetName sets the "name" field. 24 | func (uc *UserCreate) SetName(s string) *UserCreate { 25 | uc.mutation.SetName(s) 26 | return uc 27 | } 28 | 29 | // SetIsActivated sets the "isActivated" field. 30 | func (uc *UserCreate) SetIsActivated(b bool) *UserCreate { 31 | uc.mutation.SetIsActivated(b) 32 | return uc 33 | } 34 | 35 | // SetNillableIsActivated sets the "isActivated" field if the given value is not nil. 36 | func (uc *UserCreate) SetNillableIsActivated(b *bool) *UserCreate { 37 | if b != nil { 38 | uc.SetIsActivated(*b) 39 | } 40 | return uc 41 | } 42 | 43 | // SetID sets the "id" field. 44 | func (uc *UserCreate) SetID(s string) *UserCreate { 45 | uc.mutation.SetID(s) 46 | return uc 47 | } 48 | 49 | // AddProductIDs adds the "products" edge to the TourProduct entity by IDs. 50 | func (uc *UserCreate) AddProductIDs(ids ...int) *UserCreate { 51 | uc.mutation.AddProductIDs(ids...) 52 | return uc 53 | } 54 | 55 | // AddProducts adds the "products" edges to the TourProduct entity. 56 | func (uc *UserCreate) AddProducts(t ...*TourProduct) *UserCreate { 57 | ids := make([]int, len(t)) 58 | for i := range t { 59 | ids[i] = t[i].ID 60 | } 61 | return uc.AddProductIDs(ids...) 62 | } 63 | 64 | // Mutation returns the UserMutation object of the builder. 65 | func (uc *UserCreate) Mutation() *UserMutation { 66 | return uc.mutation 67 | } 68 | 69 | // Save creates the User in the database. 70 | func (uc *UserCreate) Save(ctx context.Context) (*User, error) { 71 | var ( 72 | err error 73 | node *User 74 | ) 75 | uc.defaults() 76 | if len(uc.hooks) == 0 { 77 | if err = uc.check(); err != nil { 78 | return nil, err 79 | } 80 | node, err = uc.sqlSave(ctx) 81 | } else { 82 | var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { 83 | mutation, ok := m.(*UserMutation) 84 | if !ok { 85 | return nil, fmt.Errorf("unexpected mutation type %T", m) 86 | } 87 | if err = uc.check(); err != nil { 88 | return nil, err 89 | } 90 | uc.mutation = mutation 91 | node, err = uc.sqlSave(ctx) 92 | mutation.done = true 93 | return node, err 94 | }) 95 | for i := len(uc.hooks) - 1; i >= 0; i-- { 96 | mut = uc.hooks[i](mut) 97 | } 98 | if _, err := mut.Mutate(ctx, uc.mutation); err != nil { 99 | return nil, err 100 | } 101 | } 102 | return node, err 103 | } 104 | 105 | // SaveX calls Save and panics if Save returns an error. 106 | func (uc *UserCreate) SaveX(ctx context.Context) *User { 107 | v, err := uc.Save(ctx) 108 | if err != nil { 109 | panic(err) 110 | } 111 | return v 112 | } 113 | 114 | // defaults sets the default values of the builder before save. 115 | func (uc *UserCreate) defaults() { 116 | if _, ok := uc.mutation.IsActivated(); !ok { 117 | v := user.DefaultIsActivated 118 | uc.mutation.SetIsActivated(v) 119 | } 120 | } 121 | 122 | // check runs all checks and user-defined validators on the builder. 123 | func (uc *UserCreate) check() error { 124 | if _, ok := uc.mutation.Name(); !ok { 125 | return &ValidationError{Name: "name", err: errors.New("ent: missing required field \"name\"")} 126 | } 127 | if _, ok := uc.mutation.IsActivated(); !ok { 128 | return &ValidationError{Name: "isActivated", err: errors.New("ent: missing required field \"isActivated\"")} 129 | } 130 | return nil 131 | } 132 | 133 | func (uc *UserCreate) sqlSave(ctx context.Context) (*User, error) { 134 | _node, _spec := uc.createSpec() 135 | if err := sqlgraph.CreateNode(ctx, uc.driver, _spec); err != nil { 136 | if cerr, ok := isSQLConstraintError(err); ok { 137 | err = cerr 138 | } 139 | return nil, err 140 | } 141 | return _node, nil 142 | } 143 | 144 | func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { 145 | var ( 146 | _node = &User{config: uc.config} 147 | _spec = &sqlgraph.CreateSpec{ 148 | Table: user.Table, 149 | ID: &sqlgraph.FieldSpec{ 150 | Type: field.TypeString, 151 | Column: user.FieldID, 152 | }, 153 | } 154 | ) 155 | if id, ok := uc.mutation.ID(); ok { 156 | _node.ID = id 157 | _spec.ID.Value = id 158 | } 159 | if value, ok := uc.mutation.Name(); ok { 160 | _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ 161 | Type: field.TypeString, 162 | Value: value, 163 | Column: user.FieldName, 164 | }) 165 | _node.Name = value 166 | } 167 | if value, ok := uc.mutation.IsActivated(); ok { 168 | _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ 169 | Type: field.TypeBool, 170 | Value: value, 171 | Column: user.FieldIsActivated, 172 | }) 173 | _node.IsActivated = value 174 | } 175 | if nodes := uc.mutation.ProductsIDs(); len(nodes) > 0 { 176 | edge := &sqlgraph.EdgeSpec{ 177 | Rel: sqlgraph.O2M, 178 | Inverse: false, 179 | Table: user.ProductsTable, 180 | Columns: []string{user.ProductsColumn}, 181 | Bidi: false, 182 | Target: &sqlgraph.EdgeTarget{ 183 | IDSpec: &sqlgraph.FieldSpec{ 184 | Type: field.TypeInt, 185 | Column: tourproduct.FieldID, 186 | }, 187 | }, 188 | } 189 | for _, k := range nodes { 190 | edge.Target.Nodes = append(edge.Target.Nodes, k) 191 | } 192 | _spec.Edges = append(_spec.Edges, edge) 193 | } 194 | return _node, _spec 195 | } 196 | 197 | // UserCreateBulk is the builder for creating many User entities in bulk. 198 | type UserCreateBulk struct { 199 | config 200 | builders []*UserCreate 201 | } 202 | 203 | // Save creates the User entities in the database. 204 | func (ucb *UserCreateBulk) Save(ctx context.Context) ([]*User, error) { 205 | specs := make([]*sqlgraph.CreateSpec, len(ucb.builders)) 206 | nodes := make([]*User, len(ucb.builders)) 207 | mutators := make([]Mutator, len(ucb.builders)) 208 | for i := range ucb.builders { 209 | func(i int, root context.Context) { 210 | builder := ucb.builders[i] 211 | builder.defaults() 212 | var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { 213 | mutation, ok := m.(*UserMutation) 214 | if !ok { 215 | return nil, fmt.Errorf("unexpected mutation type %T", m) 216 | } 217 | if err := builder.check(); err != nil { 218 | return nil, err 219 | } 220 | builder.mutation = mutation 221 | nodes[i], specs[i] = builder.createSpec() 222 | var err error 223 | if i < len(mutators)-1 { 224 | _, err = mutators[i+1].Mutate(root, ucb.builders[i+1].mutation) 225 | } else { 226 | // Invoke the actual operation on the latest mutation in the chain. 227 | if err = sqlgraph.BatchCreate(ctx, ucb.driver, &sqlgraph.BatchCreateSpec{Nodes: specs}); err != nil { 228 | if cerr, ok := isSQLConstraintError(err); ok { 229 | err = cerr 230 | } 231 | } 232 | } 233 | mutation.done = true 234 | if err != nil { 235 | return nil, err 236 | } 237 | return nodes[i], nil 238 | }) 239 | for i := len(builder.hooks) - 1; i >= 0; i-- { 240 | mut = builder.hooks[i](mut) 241 | } 242 | mutators[i] = mut 243 | }(i, ctx) 244 | } 245 | if len(mutators) > 0 { 246 | if _, err := mutators[0].Mutate(ctx, ucb.builders[0].mutation); err != nil { 247 | return nil, err 248 | } 249 | } 250 | return nodes, nil 251 | } 252 | 253 | // SaveX is like Save, but panics if an error occurs. 254 | func (ucb *UserCreateBulk) SaveX(ctx context.Context) []*User { 255 | v, err := ucb.Save(ctx) 256 | if err != nil { 257 | panic(err) 258 | } 259 | return v 260 | } 261 | -------------------------------------------------------------------------------- /db/ent/user_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | "db/ent/predicate" 8 | "db/ent/user" 9 | "fmt" 10 | 11 | "entgo.io/ent/dialect/sql" 12 | "entgo.io/ent/dialect/sql/sqlgraph" 13 | "entgo.io/ent/schema/field" 14 | ) 15 | 16 | // UserDelete is the builder for deleting a User entity. 17 | type UserDelete struct { 18 | config 19 | hooks []Hook 20 | mutation *UserMutation 21 | } 22 | 23 | // Where adds a new predicate to the UserDelete builder. 24 | func (ud *UserDelete) Where(ps ...predicate.User) *UserDelete { 25 | ud.mutation.predicates = append(ud.mutation.predicates, ps...) 26 | return ud 27 | } 28 | 29 | // Exec executes the deletion query and returns how many vertices were deleted. 30 | func (ud *UserDelete) Exec(ctx context.Context) (int, error) { 31 | var ( 32 | err error 33 | affected int 34 | ) 35 | if len(ud.hooks) == 0 { 36 | affected, err = ud.sqlExec(ctx) 37 | } else { 38 | var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { 39 | mutation, ok := m.(*UserMutation) 40 | if !ok { 41 | return nil, fmt.Errorf("unexpected mutation type %T", m) 42 | } 43 | ud.mutation = mutation 44 | affected, err = ud.sqlExec(ctx) 45 | mutation.done = true 46 | return affected, err 47 | }) 48 | for i := len(ud.hooks) - 1; i >= 0; i-- { 49 | mut = ud.hooks[i](mut) 50 | } 51 | if _, err := mut.Mutate(ctx, ud.mutation); err != nil { 52 | return 0, err 53 | } 54 | } 55 | return affected, err 56 | } 57 | 58 | // ExecX is like Exec, but panics if an error occurs. 59 | func (ud *UserDelete) ExecX(ctx context.Context) int { 60 | n, err := ud.Exec(ctx) 61 | if err != nil { 62 | panic(err) 63 | } 64 | return n 65 | } 66 | 67 | func (ud *UserDelete) sqlExec(ctx context.Context) (int, error) { 68 | _spec := &sqlgraph.DeleteSpec{ 69 | Node: &sqlgraph.NodeSpec{ 70 | Table: user.Table, 71 | ID: &sqlgraph.FieldSpec{ 72 | Type: field.TypeString, 73 | Column: user.FieldID, 74 | }, 75 | }, 76 | } 77 | if ps := ud.mutation.predicates; len(ps) > 0 { 78 | _spec.Predicate = func(selector *sql.Selector) { 79 | for i := range ps { 80 | ps[i](selector) 81 | } 82 | } 83 | } 84 | return sqlgraph.DeleteNodes(ctx, ud.driver, _spec) 85 | } 86 | 87 | // UserDeleteOne is the builder for deleting a single User entity. 88 | type UserDeleteOne struct { 89 | ud *UserDelete 90 | } 91 | 92 | // Exec executes the deletion query. 93 | func (udo *UserDeleteOne) Exec(ctx context.Context) error { 94 | n, err := udo.ud.Exec(ctx) 95 | switch { 96 | case err != nil: 97 | return err 98 | case n == 0: 99 | return &NotFoundError{user.Label} 100 | default: 101 | return nil 102 | } 103 | } 104 | 105 | // ExecX is like Exec, but panics if an error occurs. 106 | func (udo *UserDeleteOne) ExecX(ctx context.Context) { 107 | udo.ud.ExecX(ctx) 108 | } 109 | -------------------------------------------------------------------------------- /db/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/umi0410/how-to-backend-in-go/db 2 | 3 | go 1.16 4 | 5 | require ( 6 | entgo.io/ent v0.8.0 7 | github.com/mattn/go-sqlite3 v1.14.6 8 | ) 9 | -------------------------------------------------------------------------------- /db/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "db/ent" 6 | "db/ent/migrate" 7 | "fmt" 8 | _ "github.com/mattn/go-sqlite3" 9 | "log" 10 | ) 11 | 12 | func main(){ 13 | client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") 14 | if err != nil { 15 | log.Fatal(err) 16 | } 17 | defer client.Close() 18 | if err := client.Schema.Create( 19 | context.TODO(), 20 | migrate.WithDropIndex(true), 21 | migrate.WithDropColumn(true), 22 | ); err != nil { 23 | log.Fatalf("failed creating schema resources: %v", err) 24 | } 25 | 26 | userRepository := UserRepository{Client: client.User} 27 | tourProductRepository := TourProductRepository{Client: client.TourProduct} 28 | 29 | 30 | user1 := client.User.Create(). 31 | SetID("umi0410"). 32 | SetName("박진수"). 33 | SaveX(context.TODO()) 34 | 35 | user2 := client.User.Create(). 36 | SetID("devumi"). 37 | SetName("개발자"). 38 | SaveX(context.TODO()) 39 | 40 | client.TourProduct.Create(). 41 | SetName("미국 뉴욕 여행"). 42 | SetManager(user1). 43 | SetPrice(2000000). 44 | SaveX(context.TODO()) 45 | 46 | client.TourProduct.Create(). 47 | SetName("유럽 여행"). 48 | SetManager(user2). 49 | SetPrice(7000000). 50 | SaveX(context.TODO()) 51 | 52 | fmt.Println("전체 유저 조회") 53 | for _, user := range userRepository.FindAll() { 54 | fmt.Printf("User(id=%s, name=%s)\n", user.ID, user.Name) 55 | } 56 | fmt.Println("--------------------------------------------------------------------------") 57 | 58 | fmt.Println("전체 여행 상품 조회") 59 | for _, tour := range tourProductRepository.FindAll() { 60 | fmt.Printf("TourProduct(id=%d, name=%s, manager=%s)\n", tour.ID, tour.Name, tour.Edges.Manager.ID) 61 | } 62 | fmt.Println("--------------------------------------------------------------------------") 63 | 64 | fmt.Println(user1.ID + "가 관리하는 전체 여행 상품 조회") 65 | for _, tour := range tourProductRepository.FindAllByManager(user1.ID) { 66 | fmt.Printf("TourProduct(id=%d, name=%s, manager=%s)\n", tour.ID, tour.Name, tour.Edges.Manager.ID) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /db/repository.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "db/ent" 6 | "db/ent/tourproduct" 7 | "db/ent/user" 8 | ) 9 | 10 | type UserRepository struct{ 11 | Client *ent.UserClient 12 | } 13 | 14 | type TourProductRepository struct{ 15 | Client *ent.TourProductClient 16 | } 17 | 18 | func (repo *UserRepository) FindAll() []*ent.User{ 19 | result := repo.Client.Query(). 20 | WithProducts(). 21 | AllX(context.TODO()) 22 | 23 | return result 24 | } 25 | 26 | func (repo *TourProductRepository) FindAll() []*ent.TourProduct{ 27 | result := repo.Client.Query(). 28 | WithManager(). 29 | AllX(context.TODO()) 30 | 31 | return result 32 | } 33 | 34 | func (repo *TourProductRepository) FindAllByManager(managerID string) []*ent.TourProduct{ 35 | result := repo.Client.Query(). 36 | // 특정 manager_id의 TourProduct를 조회하도록 조인 37 | Where(tourproduct.HasManagerWith(user.ID(managerID))). 38 | WithManager(). 39 | AllX(context.TODO()) 40 | 41 | return result 42 | } -------------------------------------------------------------------------------- /errorhandle/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/umi0410/how-to-backend-in-go/errorhandle 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/gofiber/fiber/v2 v2.18.0 7 | github.com/sirupsen/logrus v1.8.1 8 | ) 9 | -------------------------------------------------------------------------------- /errorhandle/go.sum: -------------------------------------------------------------------------------- 1 | github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E= 2 | github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/gofiber/fiber/v2 v2.18.0 h1:xCWYSVoTNibHpzfciPwUSZGiTyTpTXYchCwynuJU09s= 6 | github.com/gofiber/fiber/v2 v2.18.0/go.mod h1:/LdZHMUXZvTTo7gU4+b1hclqCAdoQphNQ9bi9gutPyI= 7 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 8 | github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEEeX6s= 9 | github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= 10 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 11 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 12 | github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= 13 | github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 14 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= 15 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 16 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 17 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 18 | github.com/valyala/fasthttp v1.29.0 h1:F5GKpytwFk5OhCuRh6H+d4vZAcEeNAwPTdwQnm6IERY= 19 | github.com/valyala/fasthttp v1.29.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= 20 | github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= 21 | github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= 22 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= 23 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 24 | golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 25 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 26 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 27 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 28 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E= 29 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 30 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 31 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 32 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 33 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 34 | -------------------------------------------------------------------------------- /errorhandle/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "github.com/gofiber/fiber/v2" 7 | log "github.com/sirupsen/logrus" 8 | ) 9 | 10 | var ( 11 | ErrResourceNotFound = errors.New("존재하지 않는 리소스") 12 | users = []*User{ 13 | &User{Name: "우미잉", Age: 25, Username: "umi0410"}, 14 | } 15 | ) 16 | 17 | type User struct { 18 | Name string 19 | Age int 20 | Username string 21 | } 22 | 23 | type UserService struct{} 24 | 25 | func (svc *UserService) GetUserWorst(username string) (*User, error) { 26 | for _, user := range users { 27 | if user.Username == username { 28 | return user, nil 29 | } 30 | } 31 | 32 | return nil, errors.New("유저가 존재하지 않는 유저(username=" + username + ")") 33 | } 34 | 35 | func (svc *UserService) GetUserUngracefully(username string) (*User, error) { 36 | for _, user := range users { 37 | if user.Username == username { 38 | return user, nil 39 | } 40 | } 41 | 42 | return nil, ErrResourceNotFound 43 | } 44 | 45 | func (svc *UserService) GetUserGracefully(username string) (*User, error) { 46 | for _, user := range users { 47 | if user.Username == username { 48 | return user, nil 49 | } 50 | } 51 | 52 | return nil, fmt.Errorf("입력된 username=%s: %w", username, ErrResourceNotFound) 53 | } 54 | 55 | func main() { 56 | userService := &UserService{} 57 | app := fiber.New(fiber.Config{}) 58 | app.Use(customErrorHandler) 59 | 60 | app.Get("/worst/:username", func(ctx *fiber.Ctx) error { 61 | username := ctx.Params("username", "") 62 | user, err := userService.GetUserWorst(username) 63 | if err != nil { 64 | return err 65 | } 66 | 67 | return ctx.JSON(user) 68 | }) 69 | 70 | app.Get("/ungraceful/:username", func(ctx *fiber.Ctx) error { 71 | username := ctx.Params("username", "") 72 | user, err := userService.GetUserUngracefully(username) 73 | if err != nil { 74 | return err 75 | } 76 | 77 | return ctx.JSON(user) 78 | }) 79 | 80 | app.Get("/graceful/:username", func(ctx *fiber.Ctx) error { 81 | username := ctx.Params("username", "") 82 | user, err := userService.GetUserGracefully(username) 83 | if err != nil { 84 | return err 85 | } 86 | 87 | return ctx.JSON(user) 88 | }) 89 | 90 | app.Listen(fmt.Sprintf("0.0.0.0:%d", 8000)) 91 | } 92 | 93 | func customErrorHandler(ctx *fiber.Ctx) error { 94 | // 다음 핸들러를 호출한 뒤 95 | // 본 미들웨어의 작업은 사후처리! 96 | err := ctx.Next() 97 | if err != nil { 98 | log.Error(err) 99 | if errors.Is(err, ErrResourceNotFound) { 100 | // fiber의 Default Error Handler가 알아들을 수 있는 형태의 fiber Error을 리턴 101 | return fiber.NewError(404, err.Error()) 102 | } 103 | } 104 | 105 | return err 106 | } -------------------------------------------------------------------------------- /middleware/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/umi0410/how-to-backend-in-go/middleware 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/gofiber/fiber/v2 v2.18.0 7 | github.com/sirupsen/logrus v1.8.1 8 | ) 9 | -------------------------------------------------------------------------------- /middleware/go.sum: -------------------------------------------------------------------------------- 1 | github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E= 2 | github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/gofiber/fiber/v2 v2.18.0 h1:xCWYSVoTNibHpzfciPwUSZGiTyTpTXYchCwynuJU09s= 6 | github.com/gofiber/fiber/v2 v2.18.0/go.mod h1:/LdZHMUXZvTTo7gU4+b1hclqCAdoQphNQ9bi9gutPyI= 7 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 8 | github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEEeX6s= 9 | github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= 10 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 11 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 12 | github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= 13 | github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 14 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= 15 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 16 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 17 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 18 | github.com/valyala/fasthttp v1.29.0 h1:F5GKpytwFk5OhCuRh6H+d4vZAcEeNAwPTdwQnm6IERY= 19 | github.com/valyala/fasthttp v1.29.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus= 20 | github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= 21 | github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= 22 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= 23 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 24 | golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 25 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 26 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 27 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 28 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E= 29 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 30 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 31 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 32 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 33 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 34 | -------------------------------------------------------------------------------- /middleware/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gofiber/fiber/v2" 6 | "github.com/gofiber/fiber/v2/middleware/basicauth" 7 | log "github.com/sirupsen/logrus" 8 | "time" 9 | ) 10 | 11 | // injectLoggerMiddleware 는 요청 유저의 정보를 주입한 logger를 12 | // 요청에 대한 context에 삽입합니다. 13 | var injectLoggerMiddleware = func (ctx *fiber.Ctx) error{ 14 | // basic auth middleware가 주입한 username을 이용합니다. 15 | username := ctx.Locals("username") 16 | logger := log.WithField("user", username) 17 | // context에 logger라는 키로 유저 정보를 주입한 logger를 전달합니다! 18 | ctx.Locals("logger", logger) 19 | 20 | // 다음 미들웨어(혹은 요청 핸들러)를 수행합니다. 21 | return ctx.Next() 22 | } 23 | 24 | func main(){ 25 | // 두 가지 Config를 이용해 각각의 서버 8000, 8001에 띄웁니다. 26 | for i, config := range []*basicauth.Config{ 27 | newBasicAuthConfigAlwaysAllow(), 28 | newBasicAuthConfigAllowOnlyAdmin(), 29 | }{ 30 | app := fiber.New(fiber.Config{}) 31 | // injectLoggerMiddleware는 basicauth가 context에 주입한 username을 이용하기 때문에 32 | // 꼭 basicauth middleware 다음에 수행되어야합니다! 33 | app.Use(basicauth.New(*config)) 34 | app.Use(injectLoggerMiddleware) 35 | // JWT Middleware 36 | app.Get("", func(ctx *fiber.Ctx) error { 37 | logger := ctx.Locals("logger").(*log.Entry) 38 | logger.Info("유저가 접속했습니다") 39 | return ctx.SendString("Welcome!\n") 40 | }) 41 | 42 | go app.Listen(fmt.Sprintf("0.0.0.0:%d", 8000 +i)) 43 | } 44 | for { 45 | time.Sleep(10 * time.Second) 46 | } 47 | } 48 | 49 | // newBasicAuthConfigAlwaysAllow 는 언제나 인증에 성공하는 Authorizer를 50 | // 이용하는 Config를 만듭니다. 51 | func newBasicAuthConfigAlwaysAllow() *basicauth.Config{ 52 | return &basicauth.Config{ 53 | Authorizer: func(username string, password string) bool { 54 | return true 55 | }, 56 | } 57 | } 58 | 59 | // newBasicAuthConfigAlwaysAllow 는 Users에 존재하는 유저 정보에 대해서만 60 | // 인증에 성공하는 Authorizer를 이용하는 Config를 만듭니다. 61 | func newBasicAuthConfigAllowOnlyAdmin() *basicauth.Config{ 62 | return &basicauth.Config{ 63 | Users: map[string]string{ 64 | "foo": "bar", 65 | }, 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /testcode/datatypes.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type UserCreateInput struct{ 4 | ID string `json:"id"` 5 | Password string `json:"password"` 6 | Name string `json:"name"` 7 | } -------------------------------------------------------------------------------- /testcode/ent/client.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "log" 9 | 10 | "github.com/umi0410/how-to-backend-in-go/testcode/ent/migrate" 11 | 12 | "github.com/umi0410/how-to-backend-in-go/testcode/ent/user" 13 | 14 | "entgo.io/ent/dialect" 15 | "entgo.io/ent/dialect/sql" 16 | ) 17 | 18 | // Client is the client that holds all ent builders. 19 | type Client struct { 20 | config 21 | // Schema is the client for creating, migrating and dropping schema. 22 | Schema *migrate.Schema 23 | // User is the client for interacting with the User builders. 24 | User *UserClient 25 | } 26 | 27 | // NewClient creates a new client configured with the given options. 28 | func NewClient(opts ...Option) *Client { 29 | cfg := config{log: log.Println, hooks: &hooks{}} 30 | cfg.options(opts...) 31 | client := &Client{config: cfg} 32 | client.init() 33 | return client 34 | } 35 | 36 | func (c *Client) init() { 37 | c.Schema = migrate.NewSchema(c.driver) 38 | c.User = NewUserClient(c.config) 39 | } 40 | 41 | // Open opens a database/sql.DB specified by the driver name and 42 | // the data source name, and returns a new client attached to it. 43 | // Optional parameters can be added for configuring the client. 44 | func Open(driverName, dataSourceName string, options ...Option) (*Client, error) { 45 | switch driverName { 46 | case dialect.MySQL, dialect.Postgres, dialect.SQLite: 47 | drv, err := sql.Open(driverName, dataSourceName) 48 | if err != nil { 49 | return nil, err 50 | } 51 | return NewClient(append(options, Driver(drv))...), nil 52 | default: 53 | return nil, fmt.Errorf("unsupported driver: %q", driverName) 54 | } 55 | } 56 | 57 | // Tx returns a new transactional client. The provided context 58 | // is used until the transaction is committed or rolled back. 59 | func (c *Client) Tx(ctx context.Context) (*Tx, error) { 60 | if _, ok := c.driver.(*txDriver); ok { 61 | return nil, fmt.Errorf("ent: cannot start a transaction within a transaction") 62 | } 63 | tx, err := newTx(ctx, c.driver) 64 | if err != nil { 65 | return nil, fmt.Errorf("ent: starting a transaction: %w", err) 66 | } 67 | cfg := c.config 68 | cfg.driver = tx 69 | return &Tx{ 70 | ctx: ctx, 71 | config: cfg, 72 | User: NewUserClient(cfg), 73 | }, nil 74 | } 75 | 76 | // BeginTx returns a transactional client with specified options. 77 | func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { 78 | if _, ok := c.driver.(*txDriver); ok { 79 | return nil, fmt.Errorf("ent: cannot start a transaction within a transaction") 80 | } 81 | tx, err := c.driver.(interface { 82 | BeginTx(context.Context, *sql.TxOptions) (dialect.Tx, error) 83 | }).BeginTx(ctx, opts) 84 | if err != nil { 85 | return nil, fmt.Errorf("ent: starting a transaction: %w", err) 86 | } 87 | cfg := c.config 88 | cfg.driver = &txDriver{tx: tx, drv: c.driver} 89 | return &Tx{ 90 | config: cfg, 91 | User: NewUserClient(cfg), 92 | }, nil 93 | } 94 | 95 | // Debug returns a new debug-client. It's used to get verbose logging on specific operations. 96 | // 97 | // client.Debug(). 98 | // User. 99 | // Query(). 100 | // Count(ctx) 101 | // 102 | func (c *Client) Debug() *Client { 103 | if c.debug { 104 | return c 105 | } 106 | cfg := c.config 107 | cfg.driver = dialect.Debug(c.driver, c.log) 108 | client := &Client{config: cfg} 109 | client.init() 110 | return client 111 | } 112 | 113 | // Close closes the database connection and prevents new queries from starting. 114 | func (c *Client) Close() error { 115 | return c.driver.Close() 116 | } 117 | 118 | // Use adds the mutation hooks to all the entity clients. 119 | // In order to add hooks to a specific client, call: `client.Node.Use(...)`. 120 | func (c *Client) Use(hooks ...Hook) { 121 | c.User.Use(hooks...) 122 | } 123 | 124 | // UserClient is a client for the User schema. 125 | type UserClient struct { 126 | config 127 | } 128 | 129 | // NewUserClient returns a client for the User from the given config. 130 | func NewUserClient(c config) *UserClient { 131 | return &UserClient{config: c} 132 | } 133 | 134 | // Use adds a list of mutation hooks to the hooks stack. 135 | // A call to `Use(f, g, h)` equals to `user.Hooks(f(g(h())))`. 136 | func (c *UserClient) Use(hooks ...Hook) { 137 | c.hooks.User = append(c.hooks.User, hooks...) 138 | } 139 | 140 | // Create returns a create builder for User. 141 | func (c *UserClient) Create() *UserCreate { 142 | mutation := newUserMutation(c.config, OpCreate) 143 | return &UserCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} 144 | } 145 | 146 | // CreateBulk returns a builder for creating a bulk of User entities. 147 | func (c *UserClient) CreateBulk(builders ...*UserCreate) *UserCreateBulk { 148 | return &UserCreateBulk{config: c.config, builders: builders} 149 | } 150 | 151 | // Update returns an update builder for User. 152 | func (c *UserClient) Update() *UserUpdate { 153 | mutation := newUserMutation(c.config, OpUpdate) 154 | return &UserUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} 155 | } 156 | 157 | // UpdateOne returns an update builder for the given entity. 158 | func (c *UserClient) UpdateOne(u *User) *UserUpdateOne { 159 | mutation := newUserMutation(c.config, OpUpdateOne, withUser(u)) 160 | return &UserUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} 161 | } 162 | 163 | // UpdateOneID returns an update builder for the given id. 164 | func (c *UserClient) UpdateOneID(id string) *UserUpdateOne { 165 | mutation := newUserMutation(c.config, OpUpdateOne, withUserID(id)) 166 | return &UserUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} 167 | } 168 | 169 | // Delete returns a delete builder for User. 170 | func (c *UserClient) Delete() *UserDelete { 171 | mutation := newUserMutation(c.config, OpDelete) 172 | return &UserDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} 173 | } 174 | 175 | // DeleteOne returns a delete builder for the given entity. 176 | func (c *UserClient) DeleteOne(u *User) *UserDeleteOne { 177 | return c.DeleteOneID(u.ID) 178 | } 179 | 180 | // DeleteOneID returns a delete builder for the given id. 181 | func (c *UserClient) DeleteOneID(id string) *UserDeleteOne { 182 | builder := c.Delete().Where(user.ID(id)) 183 | builder.mutation.id = &id 184 | builder.mutation.op = OpDeleteOne 185 | return &UserDeleteOne{builder} 186 | } 187 | 188 | // Query returns a query builder for User. 189 | func (c *UserClient) Query() *UserQuery { 190 | return &UserQuery{ 191 | config: c.config, 192 | } 193 | } 194 | 195 | // Get returns a User entity by its id. 196 | func (c *UserClient) Get(ctx context.Context, id string) (*User, error) { 197 | return c.Query().Where(user.ID(id)).Only(ctx) 198 | } 199 | 200 | // GetX is like Get, but panics if an error occurs. 201 | func (c *UserClient) GetX(ctx context.Context, id string) *User { 202 | obj, err := c.Get(ctx, id) 203 | if err != nil { 204 | panic(err) 205 | } 206 | return obj 207 | } 208 | 209 | // Hooks returns the client hooks. 210 | func (c *UserClient) Hooks() []Hook { 211 | return c.hooks.User 212 | } 213 | -------------------------------------------------------------------------------- /testcode/ent/config.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "entgo.io/ent" 7 | "entgo.io/ent/dialect" 8 | ) 9 | 10 | // Option function to configure the client. 11 | type Option func(*config) 12 | 13 | // Config is the configuration for the client and its builder. 14 | type config struct { 15 | // driver used for executing database requests. 16 | driver dialect.Driver 17 | // debug enable a debug logging. 18 | debug bool 19 | // log used for logging on debug mode. 20 | log func(...interface{}) 21 | // hooks to execute on mutations. 22 | hooks *hooks 23 | } 24 | 25 | // hooks per client, for fast access. 26 | type hooks struct { 27 | User []ent.Hook 28 | } 29 | 30 | // Options applies the options on the config object. 31 | func (c *config) options(opts ...Option) { 32 | for _, opt := range opts { 33 | opt(c) 34 | } 35 | if c.debug { 36 | c.driver = dialect.Debug(c.driver, c.log) 37 | } 38 | } 39 | 40 | // Debug enables debug logging on the ent.Driver. 41 | func Debug() Option { 42 | return func(c *config) { 43 | c.debug = true 44 | } 45 | } 46 | 47 | // Log sets the logging function for debug mode. 48 | func Log(fn func(...interface{})) Option { 49 | return func(c *config) { 50 | c.log = fn 51 | } 52 | } 53 | 54 | // Driver configures the client driver. 55 | func Driver(driver dialect.Driver) Option { 56 | return func(c *config) { 57 | c.driver = driver 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /testcode/ent/context.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | ) 8 | 9 | type clientCtxKey struct{} 10 | 11 | // FromContext returns a Client stored inside a context, or nil if there isn't one. 12 | func FromContext(ctx context.Context) *Client { 13 | c, _ := ctx.Value(clientCtxKey{}).(*Client) 14 | return c 15 | } 16 | 17 | // NewContext returns a new context with the given Client attached. 18 | func NewContext(parent context.Context, c *Client) context.Context { 19 | return context.WithValue(parent, clientCtxKey{}, c) 20 | } 21 | 22 | type txCtxKey struct{} 23 | 24 | // TxFromContext returns a Tx stored inside a context, or nil if there isn't one. 25 | func TxFromContext(ctx context.Context) *Tx { 26 | tx, _ := ctx.Value(txCtxKey{}).(*Tx) 27 | return tx 28 | } 29 | 30 | // NewTxContext returns a new context with the given Tx attached. 31 | func NewTxContext(parent context.Context, tx *Tx) context.Context { 32 | return context.WithValue(parent, txCtxKey{}, tx) 33 | } 34 | -------------------------------------------------------------------------------- /testcode/ent/ent.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "errors" 7 | "fmt" 8 | 9 | "entgo.io/ent" 10 | "entgo.io/ent/dialect" 11 | "entgo.io/ent/dialect/sql" 12 | "entgo.io/ent/dialect/sql/sqlgraph" 13 | "github.com/umi0410/how-to-backend-in-go/testcode/ent/user" 14 | ) 15 | 16 | // ent aliases to avoid import conflicts in user's code. 17 | type ( 18 | Op = ent.Op 19 | Hook = ent.Hook 20 | Value = ent.Value 21 | Query = ent.Query 22 | Policy = ent.Policy 23 | Mutator = ent.Mutator 24 | Mutation = ent.Mutation 25 | MutateFunc = ent.MutateFunc 26 | ) 27 | 28 | // OrderFunc applies an ordering on the sql selector. 29 | type OrderFunc func(*sql.Selector) 30 | 31 | // columnChecker returns a function indicates if the column exists in the given column. 32 | func columnChecker(table string) func(string) error { 33 | checks := map[string]func(string) bool{ 34 | user.Table: user.ValidColumn, 35 | } 36 | check, ok := checks[table] 37 | if !ok { 38 | return func(string) error { 39 | return fmt.Errorf("unknown table %q", table) 40 | } 41 | } 42 | return func(column string) error { 43 | if !check(column) { 44 | return fmt.Errorf("unknown column %q for table %q", column, table) 45 | } 46 | return nil 47 | } 48 | } 49 | 50 | // Asc applies the given fields in ASC order. 51 | func Asc(fields ...string) OrderFunc { 52 | return func(s *sql.Selector) { 53 | check := columnChecker(s.TableName()) 54 | for _, f := range fields { 55 | if err := check(f); err != nil { 56 | s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)}) 57 | } 58 | s.OrderBy(sql.Asc(s.C(f))) 59 | } 60 | } 61 | } 62 | 63 | // Desc applies the given fields in DESC order. 64 | func Desc(fields ...string) OrderFunc { 65 | return func(s *sql.Selector) { 66 | check := columnChecker(s.TableName()) 67 | for _, f := range fields { 68 | if err := check(f); err != nil { 69 | s.AddError(&ValidationError{Name: f, err: fmt.Errorf("ent: %w", err)}) 70 | } 71 | s.OrderBy(sql.Desc(s.C(f))) 72 | } 73 | } 74 | } 75 | 76 | // AggregateFunc applies an aggregation step on the group-by traversal/selector. 77 | type AggregateFunc func(*sql.Selector) string 78 | 79 | // As is a pseudo aggregation function for renaming another other functions with custom names. For example: 80 | // 81 | // GroupBy(field1, field2). 82 | // Aggregate(ent.As(ent.Sum(field1), "sum_field1"), (ent.As(ent.Sum(field2), "sum_field2")). 83 | // Scan(ctx, &v) 84 | // 85 | func As(fn AggregateFunc, end string) AggregateFunc { 86 | return func(s *sql.Selector) string { 87 | return sql.As(fn(s), end) 88 | } 89 | } 90 | 91 | // Count applies the "count" aggregation function on each group. 92 | func Count() AggregateFunc { 93 | return func(s *sql.Selector) string { 94 | return sql.Count("*") 95 | } 96 | } 97 | 98 | // Max applies the "max" aggregation function on the given field of each group. 99 | func Max(field string) AggregateFunc { 100 | return func(s *sql.Selector) string { 101 | check := columnChecker(s.TableName()) 102 | if err := check(field); err != nil { 103 | s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) 104 | return "" 105 | } 106 | return sql.Max(s.C(field)) 107 | } 108 | } 109 | 110 | // Mean applies the "mean" aggregation function on the given field of each group. 111 | func Mean(field string) AggregateFunc { 112 | return func(s *sql.Selector) string { 113 | check := columnChecker(s.TableName()) 114 | if err := check(field); err != nil { 115 | s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) 116 | return "" 117 | } 118 | return sql.Avg(s.C(field)) 119 | } 120 | } 121 | 122 | // Min applies the "min" aggregation function on the given field of each group. 123 | func Min(field string) AggregateFunc { 124 | return func(s *sql.Selector) string { 125 | check := columnChecker(s.TableName()) 126 | if err := check(field); err != nil { 127 | s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) 128 | return "" 129 | } 130 | return sql.Min(s.C(field)) 131 | } 132 | } 133 | 134 | // Sum applies the "sum" aggregation function on the given field of each group. 135 | func Sum(field string) AggregateFunc { 136 | return func(s *sql.Selector) string { 137 | check := columnChecker(s.TableName()) 138 | if err := check(field); err != nil { 139 | s.AddError(&ValidationError{Name: field, err: fmt.Errorf("ent: %w", err)}) 140 | return "" 141 | } 142 | return sql.Sum(s.C(field)) 143 | } 144 | } 145 | 146 | // ValidationError returns when validating a field fails. 147 | type ValidationError struct { 148 | Name string // Field or edge name. 149 | err error 150 | } 151 | 152 | // Error implements the error interface. 153 | func (e *ValidationError) Error() string { 154 | return e.err.Error() 155 | } 156 | 157 | // Unwrap implements the errors.Wrapper interface. 158 | func (e *ValidationError) Unwrap() error { 159 | return e.err 160 | } 161 | 162 | // IsValidationError returns a boolean indicating whether the error is a validaton error. 163 | func IsValidationError(err error) bool { 164 | if err == nil { 165 | return false 166 | } 167 | var e *ValidationError 168 | return errors.As(err, &e) 169 | } 170 | 171 | // NotFoundError returns when trying to fetch a specific entity and it was not found in the database. 172 | type NotFoundError struct { 173 | label string 174 | } 175 | 176 | // Error implements the error interface. 177 | func (e *NotFoundError) Error() string { 178 | return "ent: " + e.label + " not found" 179 | } 180 | 181 | // IsNotFound returns a boolean indicating whether the error is a not found error. 182 | func IsNotFound(err error) bool { 183 | if err == nil { 184 | return false 185 | } 186 | var e *NotFoundError 187 | return errors.As(err, &e) 188 | } 189 | 190 | // MaskNotFound masks not found error. 191 | func MaskNotFound(err error) error { 192 | if IsNotFound(err) { 193 | return nil 194 | } 195 | return err 196 | } 197 | 198 | // NotSingularError returns when trying to fetch a singular entity and more then one was found in the database. 199 | type NotSingularError struct { 200 | label string 201 | } 202 | 203 | // Error implements the error interface. 204 | func (e *NotSingularError) Error() string { 205 | return "ent: " + e.label + " not singular" 206 | } 207 | 208 | // IsNotSingular returns a boolean indicating whether the error is a not singular error. 209 | func IsNotSingular(err error) bool { 210 | if err == nil { 211 | return false 212 | } 213 | var e *NotSingularError 214 | return errors.As(err, &e) 215 | } 216 | 217 | // NotLoadedError returns when trying to get a node that was not loaded by the query. 218 | type NotLoadedError struct { 219 | edge string 220 | } 221 | 222 | // Error implements the error interface. 223 | func (e *NotLoadedError) Error() string { 224 | return "ent: " + e.edge + " edge was not loaded" 225 | } 226 | 227 | // IsNotLoaded returns a boolean indicating whether the error is a not loaded error. 228 | func IsNotLoaded(err error) bool { 229 | if err == nil { 230 | return false 231 | } 232 | var e *NotLoadedError 233 | return errors.As(err, &e) 234 | } 235 | 236 | // ConstraintError returns when trying to create/update one or more entities and 237 | // one or more of their constraints failed. For example, violation of edge or 238 | // field uniqueness. 239 | type ConstraintError struct { 240 | msg string 241 | wrap error 242 | } 243 | 244 | // Error implements the error interface. 245 | func (e ConstraintError) Error() string { 246 | return "ent: constraint failed: " + e.msg 247 | } 248 | 249 | // Unwrap implements the errors.Wrapper interface. 250 | func (e *ConstraintError) Unwrap() error { 251 | return e.wrap 252 | } 253 | 254 | // IsConstraintError returns a boolean indicating whether the error is a constraint failure. 255 | func IsConstraintError(err error) bool { 256 | if err == nil { 257 | return false 258 | } 259 | var e *ConstraintError 260 | return errors.As(err, &e) 261 | } 262 | 263 | func isSQLConstraintError(err error) (*ConstraintError, bool) { 264 | if sqlgraph.IsConstraintError(err) { 265 | return &ConstraintError{err.Error(), err}, true 266 | } 267 | return nil, false 268 | } 269 | 270 | // rollback calls tx.Rollback and wraps the given error with the rollback error if present. 271 | func rollback(tx dialect.Tx, err error) error { 272 | if rerr := tx.Rollback(); rerr != nil { 273 | err = fmt.Errorf("%w: %v", err, rerr) 274 | } 275 | if err, ok := isSQLConstraintError(err); ok { 276 | return err 277 | } 278 | return err 279 | } 280 | -------------------------------------------------------------------------------- /testcode/ent/enttest/enttest.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package enttest 4 | 5 | import ( 6 | "context" 7 | 8 | "github.com/umi0410/how-to-backend-in-go/testcode/ent" 9 | // required by schema hooks. 10 | _ "github.com/umi0410/how-to-backend-in-go/testcode/ent/runtime" 11 | 12 | "entgo.io/ent/dialect/sql/schema" 13 | ) 14 | 15 | type ( 16 | // TestingT is the interface that is shared between 17 | // testing.T and testing.B and used by enttest. 18 | TestingT interface { 19 | FailNow() 20 | Error(...interface{}) 21 | } 22 | 23 | // Option configures client creation. 24 | Option func(*options) 25 | 26 | options struct { 27 | opts []ent.Option 28 | migrateOpts []schema.MigrateOption 29 | } 30 | ) 31 | 32 | // WithOptions forwards options to client creation. 33 | func WithOptions(opts ...ent.Option) Option { 34 | return func(o *options) { 35 | o.opts = append(o.opts, opts...) 36 | } 37 | } 38 | 39 | // WithMigrateOptions forwards options to auto migration. 40 | func WithMigrateOptions(opts ...schema.MigrateOption) Option { 41 | return func(o *options) { 42 | o.migrateOpts = append(o.migrateOpts, opts...) 43 | } 44 | } 45 | 46 | func newOptions(opts []Option) *options { 47 | o := &options{} 48 | for _, opt := range opts { 49 | opt(o) 50 | } 51 | return o 52 | } 53 | 54 | // Open calls ent.Open and auto-run migration. 55 | func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client { 56 | o := newOptions(opts) 57 | c, err := ent.Open(driverName, dataSourceName, o.opts...) 58 | if err != nil { 59 | t.Error(err) 60 | t.FailNow() 61 | } 62 | if err := c.Schema.Create(context.Background(), o.migrateOpts...); err != nil { 63 | t.Error(err) 64 | t.FailNow() 65 | } 66 | return c 67 | } 68 | 69 | // NewClient calls ent.NewClient and auto-run migration. 70 | func NewClient(t TestingT, opts ...Option) *ent.Client { 71 | o := newOptions(opts) 72 | c := ent.NewClient(o.opts...) 73 | if err := c.Schema.Create(context.Background(), o.migrateOpts...); err != nil { 74 | t.Error(err) 75 | t.FailNow() 76 | } 77 | return c 78 | } 79 | -------------------------------------------------------------------------------- /testcode/ent/generate.go: -------------------------------------------------------------------------------- 1 | package ent 2 | 3 | //go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema 4 | -------------------------------------------------------------------------------- /testcode/ent/hook/hook.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package hook 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | 9 | "github.com/umi0410/how-to-backend-in-go/testcode/ent" 10 | ) 11 | 12 | // The UserFunc type is an adapter to allow the use of ordinary 13 | // function as User mutator. 14 | type UserFunc func(context.Context, *ent.UserMutation) (ent.Value, error) 15 | 16 | // Mutate calls f(ctx, m). 17 | func (f UserFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { 18 | mv, ok := m.(*ent.UserMutation) 19 | if !ok { 20 | return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.UserMutation", m) 21 | } 22 | return f(ctx, mv) 23 | } 24 | 25 | // Condition is a hook condition function. 26 | type Condition func(context.Context, ent.Mutation) bool 27 | 28 | // And groups conditions with the AND operator. 29 | func And(first, second Condition, rest ...Condition) Condition { 30 | return func(ctx context.Context, m ent.Mutation) bool { 31 | if !first(ctx, m) || !second(ctx, m) { 32 | return false 33 | } 34 | for _, cond := range rest { 35 | if !cond(ctx, m) { 36 | return false 37 | } 38 | } 39 | return true 40 | } 41 | } 42 | 43 | // Or groups conditions with the OR operator. 44 | func Or(first, second Condition, rest ...Condition) Condition { 45 | return func(ctx context.Context, m ent.Mutation) bool { 46 | if first(ctx, m) || second(ctx, m) { 47 | return true 48 | } 49 | for _, cond := range rest { 50 | if cond(ctx, m) { 51 | return true 52 | } 53 | } 54 | return false 55 | } 56 | } 57 | 58 | // Not negates a given condition. 59 | func Not(cond Condition) Condition { 60 | return func(ctx context.Context, m ent.Mutation) bool { 61 | return !cond(ctx, m) 62 | } 63 | } 64 | 65 | // HasOp is a condition testing mutation operation. 66 | func HasOp(op ent.Op) Condition { 67 | return func(_ context.Context, m ent.Mutation) bool { 68 | return m.Op().Is(op) 69 | } 70 | } 71 | 72 | // HasAddedFields is a condition validating `.AddedField` on fields. 73 | func HasAddedFields(field string, fields ...string) Condition { 74 | return func(_ context.Context, m ent.Mutation) bool { 75 | if _, exists := m.AddedField(field); !exists { 76 | return false 77 | } 78 | for _, field := range fields { 79 | if _, exists := m.AddedField(field); !exists { 80 | return false 81 | } 82 | } 83 | return true 84 | } 85 | } 86 | 87 | // HasClearedFields is a condition validating `.FieldCleared` on fields. 88 | func HasClearedFields(field string, fields ...string) Condition { 89 | return func(_ context.Context, m ent.Mutation) bool { 90 | if exists := m.FieldCleared(field); !exists { 91 | return false 92 | } 93 | for _, field := range fields { 94 | if exists := m.FieldCleared(field); !exists { 95 | return false 96 | } 97 | } 98 | return true 99 | } 100 | } 101 | 102 | // HasFields is a condition validating `.Field` on fields. 103 | func HasFields(field string, fields ...string) Condition { 104 | return func(_ context.Context, m ent.Mutation) bool { 105 | if _, exists := m.Field(field); !exists { 106 | return false 107 | } 108 | for _, field := range fields { 109 | if _, exists := m.Field(field); !exists { 110 | return false 111 | } 112 | } 113 | return true 114 | } 115 | } 116 | 117 | // If executes the given hook under condition. 118 | // 119 | // hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) 120 | // 121 | func If(hk ent.Hook, cond Condition) ent.Hook { 122 | return func(next ent.Mutator) ent.Mutator { 123 | return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { 124 | if cond(ctx, m) { 125 | return hk(next).Mutate(ctx, m) 126 | } 127 | return next.Mutate(ctx, m) 128 | }) 129 | } 130 | } 131 | 132 | // On executes the given hook only for the given operation. 133 | // 134 | // hook.On(Log, ent.Delete|ent.Create) 135 | // 136 | func On(hk ent.Hook, op ent.Op) ent.Hook { 137 | return If(hk, HasOp(op)) 138 | } 139 | 140 | // Unless skips the given hook only for the given operation. 141 | // 142 | // hook.Unless(Log, ent.Update|ent.UpdateOne) 143 | // 144 | func Unless(hk ent.Hook, op ent.Op) ent.Hook { 145 | return If(hk, Not(HasOp(op))) 146 | } 147 | 148 | // FixedError is a hook returning a fixed error. 149 | func FixedError(err error) ent.Hook { 150 | return func(ent.Mutator) ent.Mutator { 151 | return ent.MutateFunc(func(context.Context, ent.Mutation) (ent.Value, error) { 152 | return nil, err 153 | }) 154 | } 155 | } 156 | 157 | // Reject returns a hook that rejects all operations that match op. 158 | // 159 | // func (T) Hooks() []ent.Hook { 160 | // return []ent.Hook{ 161 | // Reject(ent.Delete|ent.Update), 162 | // } 163 | // } 164 | // 165 | func Reject(op ent.Op) ent.Hook { 166 | hk := FixedError(fmt.Errorf("%s operation is not allowed", op)) 167 | return On(hk, op) 168 | } 169 | 170 | // Chain acts as a list of hooks and is effectively immutable. 171 | // Once created, it will always hold the same set of hooks in the same order. 172 | type Chain struct { 173 | hooks []ent.Hook 174 | } 175 | 176 | // NewChain creates a new chain of hooks. 177 | func NewChain(hooks ...ent.Hook) Chain { 178 | return Chain{append([]ent.Hook(nil), hooks...)} 179 | } 180 | 181 | // Hook chains the list of hooks and returns the final hook. 182 | func (c Chain) Hook() ent.Hook { 183 | return func(mutator ent.Mutator) ent.Mutator { 184 | for i := len(c.hooks) - 1; i >= 0; i-- { 185 | mutator = c.hooks[i](mutator) 186 | } 187 | return mutator 188 | } 189 | } 190 | 191 | // Append extends a chain, adding the specified hook 192 | // as the last ones in the mutation flow. 193 | func (c Chain) Append(hooks ...ent.Hook) Chain { 194 | newHooks := make([]ent.Hook, 0, len(c.hooks)+len(hooks)) 195 | newHooks = append(newHooks, c.hooks...) 196 | newHooks = append(newHooks, hooks...) 197 | return Chain{newHooks} 198 | } 199 | 200 | // Extend extends a chain, adding the specified chain 201 | // as the last ones in the mutation flow. 202 | func (c Chain) Extend(chain Chain) Chain { 203 | return c.Append(chain.hooks...) 204 | } 205 | -------------------------------------------------------------------------------- /testcode/ent/migrate/migrate.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package migrate 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "io" 9 | 10 | "entgo.io/ent/dialect" 11 | "entgo.io/ent/dialect/sql/schema" 12 | ) 13 | 14 | var ( 15 | // WithGlobalUniqueID sets the universal ids options to the migration. 16 | // If this option is enabled, ent migration will allocate a 1<<32 range 17 | // for the ids of each entity (table). 18 | // Note that this option cannot be applied on tables that already exist. 19 | WithGlobalUniqueID = schema.WithGlobalUniqueID 20 | // WithDropColumn sets the drop column option to the migration. 21 | // If this option is enabled, ent migration will drop old columns 22 | // that were used for both fields and edges. This defaults to false. 23 | WithDropColumn = schema.WithDropColumn 24 | // WithDropIndex sets the drop index option to the migration. 25 | // If this option is enabled, ent migration will drop old indexes 26 | // that were defined in the schema. This defaults to false. 27 | // Note that unique constraints are defined using `UNIQUE INDEX`, 28 | // and therefore, it's recommended to enable this option to get more 29 | // flexibility in the schema changes. 30 | WithDropIndex = schema.WithDropIndex 31 | // WithFixture sets the foreign-key renaming option to the migration when upgrading 32 | // ent from v0.1.0 (issue-#285). Defaults to false. 33 | WithFixture = schema.WithFixture 34 | // WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true. 35 | WithForeignKeys = schema.WithForeignKeys 36 | ) 37 | 38 | // Schema is the API for creating, migrating and dropping a schema. 39 | type Schema struct { 40 | drv dialect.Driver 41 | universalID bool 42 | } 43 | 44 | // NewSchema creates a new schema client. 45 | func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } 46 | 47 | // Create creates all schema resources. 48 | func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { 49 | migrate, err := schema.NewMigrate(s.drv, opts...) 50 | if err != nil { 51 | return fmt.Errorf("ent/migrate: %w", err) 52 | } 53 | return migrate.Create(ctx, Tables...) 54 | } 55 | 56 | // WriteTo writes the schema changes to w instead of running them against the database. 57 | // 58 | // if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { 59 | // log.Fatal(err) 60 | // } 61 | // 62 | func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { 63 | drv := &schema.WriteDriver{ 64 | Writer: w, 65 | Driver: s.drv, 66 | } 67 | migrate, err := schema.NewMigrate(drv, opts...) 68 | if err != nil { 69 | return fmt.Errorf("ent/migrate: %w", err) 70 | } 71 | return migrate.Create(ctx, Tables...) 72 | } 73 | -------------------------------------------------------------------------------- /testcode/ent/migrate/schema.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package migrate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql/schema" 7 | "entgo.io/ent/schema/field" 8 | ) 9 | 10 | var ( 11 | // UsersColumns holds the columns for the "users" table. 12 | UsersColumns = []*schema.Column{ 13 | {Name: "id", Type: field.TypeString}, 14 | {Name: "password", Type: field.TypeString}, 15 | {Name: "name", Type: field.TypeString}, 16 | } 17 | // UsersTable holds the schema information for the "users" table. 18 | UsersTable = &schema.Table{ 19 | Name: "users", 20 | Columns: UsersColumns, 21 | PrimaryKey: []*schema.Column{UsersColumns[0]}, 22 | ForeignKeys: []*schema.ForeignKey{}, 23 | } 24 | // Tables holds all the tables in the schema. 25 | Tables = []*schema.Table{ 26 | UsersTable, 27 | } 28 | ) 29 | 30 | func init() { 31 | } 32 | -------------------------------------------------------------------------------- /testcode/ent/mutation.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | "sync" 9 | 10 | "github.com/umi0410/how-to-backend-in-go/testcode/ent/predicate" 11 | "github.com/umi0410/how-to-backend-in-go/testcode/ent/user" 12 | 13 | "entgo.io/ent" 14 | ) 15 | 16 | const ( 17 | // Operation types. 18 | OpCreate = ent.OpCreate 19 | OpDelete = ent.OpDelete 20 | OpDeleteOne = ent.OpDeleteOne 21 | OpUpdate = ent.OpUpdate 22 | OpUpdateOne = ent.OpUpdateOne 23 | 24 | // Node types. 25 | TypeUser = "User" 26 | ) 27 | 28 | // UserMutation represents an operation that mutates the User nodes in the graph. 29 | type UserMutation struct { 30 | config 31 | op Op 32 | typ string 33 | id *string 34 | password *string 35 | name *string 36 | clearedFields map[string]struct{} 37 | done bool 38 | oldValue func(context.Context) (*User, error) 39 | predicates []predicate.User 40 | } 41 | 42 | var _ ent.Mutation = (*UserMutation)(nil) 43 | 44 | // userOption allows management of the mutation configuration using functional options. 45 | type userOption func(*UserMutation) 46 | 47 | // newUserMutation creates new mutation for the User entity. 48 | func newUserMutation(c config, op Op, opts ...userOption) *UserMutation { 49 | m := &UserMutation{ 50 | config: c, 51 | op: op, 52 | typ: TypeUser, 53 | clearedFields: make(map[string]struct{}), 54 | } 55 | for _, opt := range opts { 56 | opt(m) 57 | } 58 | return m 59 | } 60 | 61 | // withUserID sets the ID field of the mutation. 62 | func withUserID(id string) userOption { 63 | return func(m *UserMutation) { 64 | var ( 65 | err error 66 | once sync.Once 67 | value *User 68 | ) 69 | m.oldValue = func(ctx context.Context) (*User, error) { 70 | once.Do(func() { 71 | if m.done { 72 | err = fmt.Errorf("querying old values post mutation is not allowed") 73 | } else { 74 | value, err = m.Client().User.Get(ctx, id) 75 | } 76 | }) 77 | return value, err 78 | } 79 | m.id = &id 80 | } 81 | } 82 | 83 | // withUser sets the old User of the mutation. 84 | func withUser(node *User) userOption { 85 | return func(m *UserMutation) { 86 | m.oldValue = func(context.Context) (*User, error) { 87 | return node, nil 88 | } 89 | m.id = &node.ID 90 | } 91 | } 92 | 93 | // Client returns a new `ent.Client` from the mutation. If the mutation was 94 | // executed in a transaction (ent.Tx), a transactional client is returned. 95 | func (m UserMutation) Client() *Client { 96 | client := &Client{config: m.config} 97 | client.init() 98 | return client 99 | } 100 | 101 | // Tx returns an `ent.Tx` for mutations that were executed in transactions; 102 | // it returns an error otherwise. 103 | func (m UserMutation) Tx() (*Tx, error) { 104 | if _, ok := m.driver.(*txDriver); !ok { 105 | return nil, fmt.Errorf("ent: mutation is not running in a transaction") 106 | } 107 | tx := &Tx{config: m.config} 108 | tx.init() 109 | return tx, nil 110 | } 111 | 112 | // SetID sets the value of the id field. Note that this 113 | // operation is only accepted on creation of User entities. 114 | func (m *UserMutation) SetID(id string) { 115 | m.id = &id 116 | } 117 | 118 | // ID returns the ID value in the mutation. Note that the ID 119 | // is only available if it was provided to the builder. 120 | func (m *UserMutation) ID() (id string, exists bool) { 121 | if m.id == nil { 122 | return 123 | } 124 | return *m.id, true 125 | } 126 | 127 | // SetPassword sets the "password" field. 128 | func (m *UserMutation) SetPassword(s string) { 129 | m.password = &s 130 | } 131 | 132 | // Password returns the value of the "password" field in the mutation. 133 | func (m *UserMutation) Password() (r string, exists bool) { 134 | v := m.password 135 | if v == nil { 136 | return 137 | } 138 | return *v, true 139 | } 140 | 141 | // OldPassword returns the old "password" field's value of the User entity. 142 | // If the User object wasn't provided to the builder, the object is fetched from the database. 143 | // An error is returned if the mutation operation is not UpdateOne, or the database query fails. 144 | func (m *UserMutation) OldPassword(ctx context.Context) (v string, err error) { 145 | if !m.op.Is(OpUpdateOne) { 146 | return v, fmt.Errorf("OldPassword is only allowed on UpdateOne operations") 147 | } 148 | if m.id == nil || m.oldValue == nil { 149 | return v, fmt.Errorf("OldPassword requires an ID field in the mutation") 150 | } 151 | oldValue, err := m.oldValue(ctx) 152 | if err != nil { 153 | return v, fmt.Errorf("querying old value for OldPassword: %w", err) 154 | } 155 | return oldValue.Password, nil 156 | } 157 | 158 | // ResetPassword resets all changes to the "password" field. 159 | func (m *UserMutation) ResetPassword() { 160 | m.password = nil 161 | } 162 | 163 | // SetName sets the "name" field. 164 | func (m *UserMutation) SetName(s string) { 165 | m.name = &s 166 | } 167 | 168 | // Name returns the value of the "name" field in the mutation. 169 | func (m *UserMutation) Name() (r string, exists bool) { 170 | v := m.name 171 | if v == nil { 172 | return 173 | } 174 | return *v, true 175 | } 176 | 177 | // OldName returns the old "name" field's value of the User entity. 178 | // If the User object wasn't provided to the builder, the object is fetched from the database. 179 | // An error is returned if the mutation operation is not UpdateOne, or the database query fails. 180 | func (m *UserMutation) OldName(ctx context.Context) (v string, err error) { 181 | if !m.op.Is(OpUpdateOne) { 182 | return v, fmt.Errorf("OldName is only allowed on UpdateOne operations") 183 | } 184 | if m.id == nil || m.oldValue == nil { 185 | return v, fmt.Errorf("OldName requires an ID field in the mutation") 186 | } 187 | oldValue, err := m.oldValue(ctx) 188 | if err != nil { 189 | return v, fmt.Errorf("querying old value for OldName: %w", err) 190 | } 191 | return oldValue.Name, nil 192 | } 193 | 194 | // ResetName resets all changes to the "name" field. 195 | func (m *UserMutation) ResetName() { 196 | m.name = nil 197 | } 198 | 199 | // Op returns the operation name. 200 | func (m *UserMutation) Op() Op { 201 | return m.op 202 | } 203 | 204 | // Type returns the node type of this mutation (User). 205 | func (m *UserMutation) Type() string { 206 | return m.typ 207 | } 208 | 209 | // Fields returns all fields that were changed during this mutation. Note that in 210 | // order to get all numeric fields that were incremented/decremented, call 211 | // AddedFields(). 212 | func (m *UserMutation) Fields() []string { 213 | fields := make([]string, 0, 2) 214 | if m.password != nil { 215 | fields = append(fields, user.FieldPassword) 216 | } 217 | if m.name != nil { 218 | fields = append(fields, user.FieldName) 219 | } 220 | return fields 221 | } 222 | 223 | // Field returns the value of a field with the given name. The second boolean 224 | // return value indicates that this field was not set, or was not defined in the 225 | // schema. 226 | func (m *UserMutation) Field(name string) (ent.Value, bool) { 227 | switch name { 228 | case user.FieldPassword: 229 | return m.Password() 230 | case user.FieldName: 231 | return m.Name() 232 | } 233 | return nil, false 234 | } 235 | 236 | // OldField returns the old value of the field from the database. An error is 237 | // returned if the mutation operation is not UpdateOne, or the query to the 238 | // database failed. 239 | func (m *UserMutation) OldField(ctx context.Context, name string) (ent.Value, error) { 240 | switch name { 241 | case user.FieldPassword: 242 | return m.OldPassword(ctx) 243 | case user.FieldName: 244 | return m.OldName(ctx) 245 | } 246 | return nil, fmt.Errorf("unknown User field %s", name) 247 | } 248 | 249 | // SetField sets the value of a field with the given name. It returns an error if 250 | // the field is not defined in the schema, or if the type mismatched the field 251 | // type. 252 | func (m *UserMutation) SetField(name string, value ent.Value) error { 253 | switch name { 254 | case user.FieldPassword: 255 | v, ok := value.(string) 256 | if !ok { 257 | return fmt.Errorf("unexpected type %T for field %s", value, name) 258 | } 259 | m.SetPassword(v) 260 | return nil 261 | case user.FieldName: 262 | v, ok := value.(string) 263 | if !ok { 264 | return fmt.Errorf("unexpected type %T for field %s", value, name) 265 | } 266 | m.SetName(v) 267 | return nil 268 | } 269 | return fmt.Errorf("unknown User field %s", name) 270 | } 271 | 272 | // AddedFields returns all numeric fields that were incremented/decremented during 273 | // this mutation. 274 | func (m *UserMutation) AddedFields() []string { 275 | return nil 276 | } 277 | 278 | // AddedField returns the numeric value that was incremented/decremented on a field 279 | // with the given name. The second boolean return value indicates that this field 280 | // was not set, or was not defined in the schema. 281 | func (m *UserMutation) AddedField(name string) (ent.Value, bool) { 282 | return nil, false 283 | } 284 | 285 | // AddField adds the value to the field with the given name. It returns an error if 286 | // the field is not defined in the schema, or if the type mismatched the field 287 | // type. 288 | func (m *UserMutation) AddField(name string, value ent.Value) error { 289 | switch name { 290 | } 291 | return fmt.Errorf("unknown User numeric field %s", name) 292 | } 293 | 294 | // ClearedFields returns all nullable fields that were cleared during this 295 | // mutation. 296 | func (m *UserMutation) ClearedFields() []string { 297 | return nil 298 | } 299 | 300 | // FieldCleared returns a boolean indicating if a field with the given name was 301 | // cleared in this mutation. 302 | func (m *UserMutation) FieldCleared(name string) bool { 303 | _, ok := m.clearedFields[name] 304 | return ok 305 | } 306 | 307 | // ClearField clears the value of the field with the given name. It returns an 308 | // error if the field is not defined in the schema. 309 | func (m *UserMutation) ClearField(name string) error { 310 | return fmt.Errorf("unknown User nullable field %s", name) 311 | } 312 | 313 | // ResetField resets all changes in the mutation for the field with the given name. 314 | // It returns an error if the field is not defined in the schema. 315 | func (m *UserMutation) ResetField(name string) error { 316 | switch name { 317 | case user.FieldPassword: 318 | m.ResetPassword() 319 | return nil 320 | case user.FieldName: 321 | m.ResetName() 322 | return nil 323 | } 324 | return fmt.Errorf("unknown User field %s", name) 325 | } 326 | 327 | // AddedEdges returns all edge names that were set/added in this mutation. 328 | func (m *UserMutation) AddedEdges() []string { 329 | edges := make([]string, 0, 0) 330 | return edges 331 | } 332 | 333 | // AddedIDs returns all IDs (to other nodes) that were added for the given edge 334 | // name in this mutation. 335 | func (m *UserMutation) AddedIDs(name string) []ent.Value { 336 | return nil 337 | } 338 | 339 | // RemovedEdges returns all edge names that were removed in this mutation. 340 | func (m *UserMutation) RemovedEdges() []string { 341 | edges := make([]string, 0, 0) 342 | return edges 343 | } 344 | 345 | // RemovedIDs returns all IDs (to other nodes) that were removed for the edge with 346 | // the given name in this mutation. 347 | func (m *UserMutation) RemovedIDs(name string) []ent.Value { 348 | return nil 349 | } 350 | 351 | // ClearedEdges returns all edge names that were cleared in this mutation. 352 | func (m *UserMutation) ClearedEdges() []string { 353 | edges := make([]string, 0, 0) 354 | return edges 355 | } 356 | 357 | // EdgeCleared returns a boolean which indicates if the edge with the given name 358 | // was cleared in this mutation. 359 | func (m *UserMutation) EdgeCleared(name string) bool { 360 | return false 361 | } 362 | 363 | // ClearEdge clears the value of the edge with the given name. It returns an error 364 | // if that edge is not defined in the schema. 365 | func (m *UserMutation) ClearEdge(name string) error { 366 | return fmt.Errorf("unknown User unique edge %s", name) 367 | } 368 | 369 | // ResetEdge resets all changes to the edge with the given name in this mutation. 370 | // It returns an error if the edge is not defined in the schema. 371 | func (m *UserMutation) ResetEdge(name string) error { 372 | return fmt.Errorf("unknown User edge %s", name) 373 | } 374 | -------------------------------------------------------------------------------- /testcode/ent/predicate/predicate.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package predicate 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | ) 8 | 9 | // User is the predicate function for user builders. 10 | type User func(*sql.Selector) 11 | -------------------------------------------------------------------------------- /testcode/ent/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | // The init function reads all schema descriptors with runtime code 6 | // (default values, validators, hooks and policies) and stitches it 7 | // to their package variables. 8 | func init() { 9 | } 10 | -------------------------------------------------------------------------------- /testcode/ent/runtime/runtime.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package runtime 4 | 5 | // The schema-stitching logic is generated in github.com/umi0410/how-to-backend-in-go/testcode/ent/runtime.go 6 | 7 | const ( 8 | Version = "v0.8.0" // Version of ent codegen. 9 | Sum = "h1:xirrW//1oda7pp0bz+XssSOv4/C3nmgYQOxjIfljFt8=" // Sum of ent codegen. 10 | ) 11 | -------------------------------------------------------------------------------- /testcode/ent/schema/user.go: -------------------------------------------------------------------------------- 1 | package schema 2 | 3 | import ( 4 | "entgo.io/ent" 5 | "entgo.io/ent/schema/field" 6 | ) 7 | 8 | // User holds the schema definition for the User entity. 9 | type User struct { 10 | ent.Schema 11 | } 12 | 13 | // Fields of the User. 14 | func (User) Fields() []ent.Field { 15 | return []ent.Field{ 16 | // 타입을 기반으로 안전하고 편리하게 컬럼을 정의할 수 있습니다. 17 | field.String("id"), 18 | field.String("password"), 19 | field.String("name"), 20 | } 21 | } 22 | 23 | // Edges of the User. 24 | func (User) Edges() []ent.Edge { 25 | return nil 26 | } -------------------------------------------------------------------------------- /testcode/ent/tx.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | "sync" 8 | 9 | "entgo.io/ent/dialect" 10 | ) 11 | 12 | // Tx is a transactional client that is created by calling Client.Tx(). 13 | type Tx struct { 14 | config 15 | // User is the client for interacting with the User builders. 16 | User *UserClient 17 | 18 | // lazily loaded. 19 | client *Client 20 | clientOnce sync.Once 21 | 22 | // completion callbacks. 23 | mu sync.Mutex 24 | onCommit []CommitHook 25 | onRollback []RollbackHook 26 | 27 | // ctx lives for the life of the transaction. It is 28 | // the same context used by the underlying connection. 29 | ctx context.Context 30 | } 31 | 32 | type ( 33 | // Committer is the interface that wraps the Committer method. 34 | Committer interface { 35 | Commit(context.Context, *Tx) error 36 | } 37 | 38 | // The CommitFunc type is an adapter to allow the use of ordinary 39 | // function as a Committer. If f is a function with the appropriate 40 | // signature, CommitFunc(f) is a Committer that calls f. 41 | CommitFunc func(context.Context, *Tx) error 42 | 43 | // CommitHook defines the "commit middleware". A function that gets a Committer 44 | // and returns a Committer. For example: 45 | // 46 | // hook := func(next ent.Committer) ent.Committer { 47 | // return ent.CommitFunc(func(context.Context, tx *ent.Tx) error { 48 | // // Do some stuff before. 49 | // if err := next.Commit(ctx, tx); err != nil { 50 | // return err 51 | // } 52 | // // Do some stuff after. 53 | // return nil 54 | // }) 55 | // } 56 | // 57 | CommitHook func(Committer) Committer 58 | ) 59 | 60 | // Commit calls f(ctx, m). 61 | func (f CommitFunc) Commit(ctx context.Context, tx *Tx) error { 62 | return f(ctx, tx) 63 | } 64 | 65 | // Commit commits the transaction. 66 | func (tx *Tx) Commit() error { 67 | txDriver := tx.config.driver.(*txDriver) 68 | var fn Committer = CommitFunc(func(context.Context, *Tx) error { 69 | return txDriver.tx.Commit() 70 | }) 71 | tx.mu.Lock() 72 | hooks := append([]CommitHook(nil), tx.onCommit...) 73 | tx.mu.Unlock() 74 | for i := len(hooks) - 1; i >= 0; i-- { 75 | fn = hooks[i](fn) 76 | } 77 | return fn.Commit(tx.ctx, tx) 78 | } 79 | 80 | // OnCommit adds a hook to call on commit. 81 | func (tx *Tx) OnCommit(f CommitHook) { 82 | tx.mu.Lock() 83 | defer tx.mu.Unlock() 84 | tx.onCommit = append(tx.onCommit, f) 85 | } 86 | 87 | type ( 88 | // Rollbacker is the interface that wraps the Rollbacker method. 89 | Rollbacker interface { 90 | Rollback(context.Context, *Tx) error 91 | } 92 | 93 | // The RollbackFunc type is an adapter to allow the use of ordinary 94 | // function as a Rollbacker. If f is a function with the appropriate 95 | // signature, RollbackFunc(f) is a Rollbacker that calls f. 96 | RollbackFunc func(context.Context, *Tx) error 97 | 98 | // RollbackHook defines the "rollback middleware". A function that gets a Rollbacker 99 | // and returns a Rollbacker. For example: 100 | // 101 | // hook := func(next ent.Rollbacker) ent.Rollbacker { 102 | // return ent.RollbackFunc(func(context.Context, tx *ent.Tx) error { 103 | // // Do some stuff before. 104 | // if err := next.Rollback(ctx, tx); err != nil { 105 | // return err 106 | // } 107 | // // Do some stuff after. 108 | // return nil 109 | // }) 110 | // } 111 | // 112 | RollbackHook func(Rollbacker) Rollbacker 113 | ) 114 | 115 | // Rollback calls f(ctx, m). 116 | func (f RollbackFunc) Rollback(ctx context.Context, tx *Tx) error { 117 | return f(ctx, tx) 118 | } 119 | 120 | // Rollback rollbacks the transaction. 121 | func (tx *Tx) Rollback() error { 122 | txDriver := tx.config.driver.(*txDriver) 123 | var fn Rollbacker = RollbackFunc(func(context.Context, *Tx) error { 124 | return txDriver.tx.Rollback() 125 | }) 126 | tx.mu.Lock() 127 | hooks := append([]RollbackHook(nil), tx.onRollback...) 128 | tx.mu.Unlock() 129 | for i := len(hooks) - 1; i >= 0; i-- { 130 | fn = hooks[i](fn) 131 | } 132 | return fn.Rollback(tx.ctx, tx) 133 | } 134 | 135 | // OnRollback adds a hook to call on rollback. 136 | func (tx *Tx) OnRollback(f RollbackHook) { 137 | tx.mu.Lock() 138 | defer tx.mu.Unlock() 139 | tx.onRollback = append(tx.onRollback, f) 140 | } 141 | 142 | // Client returns a Client that binds to current transaction. 143 | func (tx *Tx) Client() *Client { 144 | tx.clientOnce.Do(func() { 145 | tx.client = &Client{config: tx.config} 146 | tx.client.init() 147 | }) 148 | return tx.client 149 | } 150 | 151 | func (tx *Tx) init() { 152 | tx.User = NewUserClient(tx.config) 153 | } 154 | 155 | // txDriver wraps the given dialect.Tx with a nop dialect.Driver implementation. 156 | // The idea is to support transactions without adding any extra code to the builders. 157 | // When a builder calls to driver.Tx(), it gets the same dialect.Tx instance. 158 | // Commit and Rollback are nop for the internal builders and the user must call one 159 | // of them in order to commit or rollback the transaction. 160 | // 161 | // If a closed transaction is embedded in one of the generated entities, and the entity 162 | // applies a query, for example: User.QueryXXX(), the query will be executed 163 | // through the driver which created this transaction. 164 | // 165 | // Note that txDriver is not goroutine safe. 166 | type txDriver struct { 167 | // the driver we started the transaction from. 168 | drv dialect.Driver 169 | // tx is the underlying transaction. 170 | tx dialect.Tx 171 | } 172 | 173 | // newTx creates a new transactional driver. 174 | func newTx(ctx context.Context, drv dialect.Driver) (*txDriver, error) { 175 | tx, err := drv.Tx(ctx) 176 | if err != nil { 177 | return nil, err 178 | } 179 | return &txDriver{tx: tx, drv: drv}, nil 180 | } 181 | 182 | // Tx returns the transaction wrapper (txDriver) to avoid Commit or Rollback calls 183 | // from the internal builders. Should be called only by the internal builders. 184 | func (tx *txDriver) Tx(context.Context) (dialect.Tx, error) { return tx, nil } 185 | 186 | // Dialect returns the dialect of the driver we started the transaction from. 187 | func (tx *txDriver) Dialect() string { return tx.drv.Dialect() } 188 | 189 | // Close is a nop close. 190 | func (*txDriver) Close() error { return nil } 191 | 192 | // Commit is a nop commit for the internal builders. 193 | // User must call `Tx.Commit` in order to commit the transaction. 194 | func (*txDriver) Commit() error { return nil } 195 | 196 | // Rollback is a nop rollback for the internal builders. 197 | // User must call `Tx.Rollback` in order to rollback the transaction. 198 | func (*txDriver) Rollback() error { return nil } 199 | 200 | // Exec calls tx.Exec. 201 | func (tx *txDriver) Exec(ctx context.Context, query string, args, v interface{}) error { 202 | return tx.tx.Exec(ctx, query, args, v) 203 | } 204 | 205 | // Query calls tx.Query. 206 | func (tx *txDriver) Query(ctx context.Context, query string, args, v interface{}) error { 207 | return tx.tx.Query(ctx, query, args, v) 208 | } 209 | 210 | var _ dialect.Driver = (*txDriver)(nil) 211 | -------------------------------------------------------------------------------- /testcode/ent/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "fmt" 7 | "strings" 8 | 9 | "entgo.io/ent/dialect/sql" 10 | "github.com/umi0410/how-to-backend-in-go/testcode/ent/user" 11 | ) 12 | 13 | // User is the model entity for the User schema. 14 | type User struct { 15 | config `json:"-"` 16 | // ID of the ent. 17 | ID string `json:"id,omitempty"` 18 | // Password holds the value of the "password" field. 19 | Password string `json:"password,omitempty"` 20 | // Name holds the value of the "name" field. 21 | Name string `json:"name,omitempty"` 22 | } 23 | 24 | // scanValues returns the types for scanning values from sql.Rows. 25 | func (*User) scanValues(columns []string) ([]interface{}, error) { 26 | values := make([]interface{}, len(columns)) 27 | for i := range columns { 28 | switch columns[i] { 29 | case user.FieldID, user.FieldPassword, user.FieldName: 30 | values[i] = new(sql.NullString) 31 | default: 32 | return nil, fmt.Errorf("unexpected column %q for type User", columns[i]) 33 | } 34 | } 35 | return values, nil 36 | } 37 | 38 | // assignValues assigns the values that were returned from sql.Rows (after scanning) 39 | // to the User fields. 40 | func (u *User) assignValues(columns []string, values []interface{}) error { 41 | if m, n := len(values), len(columns); m < n { 42 | return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) 43 | } 44 | for i := range columns { 45 | switch columns[i] { 46 | case user.FieldID: 47 | if value, ok := values[i].(*sql.NullString); !ok { 48 | return fmt.Errorf("unexpected type %T for field id", values[i]) 49 | } else if value.Valid { 50 | u.ID = value.String 51 | } 52 | case user.FieldPassword: 53 | if value, ok := values[i].(*sql.NullString); !ok { 54 | return fmt.Errorf("unexpected type %T for field password", values[i]) 55 | } else if value.Valid { 56 | u.Password = value.String 57 | } 58 | case user.FieldName: 59 | if value, ok := values[i].(*sql.NullString); !ok { 60 | return fmt.Errorf("unexpected type %T for field name", values[i]) 61 | } else if value.Valid { 62 | u.Name = value.String 63 | } 64 | } 65 | } 66 | return nil 67 | } 68 | 69 | // Update returns a builder for updating this User. 70 | // Note that you need to call User.Unwrap() before calling this method if this User 71 | // was returned from a transaction, and the transaction was committed or rolled back. 72 | func (u *User) Update() *UserUpdateOne { 73 | return (&UserClient{config: u.config}).UpdateOne(u) 74 | } 75 | 76 | // Unwrap unwraps the User entity that was returned from a transaction after it was closed, 77 | // so that all future queries will be executed through the driver which created the transaction. 78 | func (u *User) Unwrap() *User { 79 | tx, ok := u.config.driver.(*txDriver) 80 | if !ok { 81 | panic("ent: User is not a transactional entity") 82 | } 83 | u.config.driver = tx.drv 84 | return u 85 | } 86 | 87 | // String implements the fmt.Stringer. 88 | func (u *User) String() string { 89 | var builder strings.Builder 90 | builder.WriteString("User(") 91 | builder.WriteString(fmt.Sprintf("id=%v", u.ID)) 92 | builder.WriteString(", password=") 93 | builder.WriteString(u.Password) 94 | builder.WriteString(", name=") 95 | builder.WriteString(u.Name) 96 | builder.WriteByte(')') 97 | return builder.String() 98 | } 99 | 100 | // Users is a parsable slice of User. 101 | type Users []*User 102 | 103 | func (u Users) config(cfg config) { 104 | for _i := range u { 105 | u[_i].config = cfg 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /testcode/ent/user/user.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package user 4 | 5 | const ( 6 | // Label holds the string label denoting the user type in the database. 7 | Label = "user" 8 | // FieldID holds the string denoting the id field in the database. 9 | FieldID = "id" 10 | // FieldPassword holds the string denoting the password field in the database. 11 | FieldPassword = "password" 12 | // FieldName holds the string denoting the name field in the database. 13 | FieldName = "name" 14 | // Table holds the table name of the user in the database. 15 | Table = "users" 16 | ) 17 | 18 | // Columns holds all SQL columns for user fields. 19 | var Columns = []string{ 20 | FieldID, 21 | FieldPassword, 22 | FieldName, 23 | } 24 | 25 | // ValidColumn reports if the column name is valid (part of the table columns). 26 | func ValidColumn(column string) bool { 27 | for i := range Columns { 28 | if column == Columns[i] { 29 | return true 30 | } 31 | } 32 | return false 33 | } 34 | -------------------------------------------------------------------------------- /testcode/ent/user/where.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package user 4 | 5 | import ( 6 | "entgo.io/ent/dialect/sql" 7 | "github.com/umi0410/how-to-backend-in-go/testcode/ent/predicate" 8 | ) 9 | 10 | // ID filters vertices based on their ID field. 11 | func ID(id string) predicate.User { 12 | return predicate.User(func(s *sql.Selector) { 13 | s.Where(sql.EQ(s.C(FieldID), id)) 14 | }) 15 | } 16 | 17 | // IDEQ applies the EQ predicate on the ID field. 18 | func IDEQ(id string) predicate.User { 19 | return predicate.User(func(s *sql.Selector) { 20 | s.Where(sql.EQ(s.C(FieldID), id)) 21 | }) 22 | } 23 | 24 | // IDNEQ applies the NEQ predicate on the ID field. 25 | func IDNEQ(id string) predicate.User { 26 | return predicate.User(func(s *sql.Selector) { 27 | s.Where(sql.NEQ(s.C(FieldID), id)) 28 | }) 29 | } 30 | 31 | // IDIn applies the In predicate on the ID field. 32 | func IDIn(ids ...string) predicate.User { 33 | return predicate.User(func(s *sql.Selector) { 34 | // if not arguments were provided, append the FALSE constants, 35 | // since we can't apply "IN ()". This will make this predicate falsy. 36 | if len(ids) == 0 { 37 | s.Where(sql.False()) 38 | return 39 | } 40 | v := make([]interface{}, len(ids)) 41 | for i := range v { 42 | v[i] = ids[i] 43 | } 44 | s.Where(sql.In(s.C(FieldID), v...)) 45 | }) 46 | } 47 | 48 | // IDNotIn applies the NotIn predicate on the ID field. 49 | func IDNotIn(ids ...string) predicate.User { 50 | return predicate.User(func(s *sql.Selector) { 51 | // if not arguments were provided, append the FALSE constants, 52 | // since we can't apply "IN ()". This will make this predicate falsy. 53 | if len(ids) == 0 { 54 | s.Where(sql.False()) 55 | return 56 | } 57 | v := make([]interface{}, len(ids)) 58 | for i := range v { 59 | v[i] = ids[i] 60 | } 61 | s.Where(sql.NotIn(s.C(FieldID), v...)) 62 | }) 63 | } 64 | 65 | // IDGT applies the GT predicate on the ID field. 66 | func IDGT(id string) predicate.User { 67 | return predicate.User(func(s *sql.Selector) { 68 | s.Where(sql.GT(s.C(FieldID), id)) 69 | }) 70 | } 71 | 72 | // IDGTE applies the GTE predicate on the ID field. 73 | func IDGTE(id string) predicate.User { 74 | return predicate.User(func(s *sql.Selector) { 75 | s.Where(sql.GTE(s.C(FieldID), id)) 76 | }) 77 | } 78 | 79 | // IDLT applies the LT predicate on the ID field. 80 | func IDLT(id string) predicate.User { 81 | return predicate.User(func(s *sql.Selector) { 82 | s.Where(sql.LT(s.C(FieldID), id)) 83 | }) 84 | } 85 | 86 | // IDLTE applies the LTE predicate on the ID field. 87 | func IDLTE(id string) predicate.User { 88 | return predicate.User(func(s *sql.Selector) { 89 | s.Where(sql.LTE(s.C(FieldID), id)) 90 | }) 91 | } 92 | 93 | // Password applies equality check predicate on the "password" field. It's identical to PasswordEQ. 94 | func Password(v string) predicate.User { 95 | return predicate.User(func(s *sql.Selector) { 96 | s.Where(sql.EQ(s.C(FieldPassword), v)) 97 | }) 98 | } 99 | 100 | // Name applies equality check predicate on the "name" field. It's identical to NameEQ. 101 | func Name(v string) predicate.User { 102 | return predicate.User(func(s *sql.Selector) { 103 | s.Where(sql.EQ(s.C(FieldName), v)) 104 | }) 105 | } 106 | 107 | // PasswordEQ applies the EQ predicate on the "password" field. 108 | func PasswordEQ(v string) predicate.User { 109 | return predicate.User(func(s *sql.Selector) { 110 | s.Where(sql.EQ(s.C(FieldPassword), v)) 111 | }) 112 | } 113 | 114 | // PasswordNEQ applies the NEQ predicate on the "password" field. 115 | func PasswordNEQ(v string) predicate.User { 116 | return predicate.User(func(s *sql.Selector) { 117 | s.Where(sql.NEQ(s.C(FieldPassword), v)) 118 | }) 119 | } 120 | 121 | // PasswordIn applies the In predicate on the "password" field. 122 | func PasswordIn(vs ...string) predicate.User { 123 | v := make([]interface{}, len(vs)) 124 | for i := range v { 125 | v[i] = vs[i] 126 | } 127 | return predicate.User(func(s *sql.Selector) { 128 | // if not arguments were provided, append the FALSE constants, 129 | // since we can't apply "IN ()". This will make this predicate falsy. 130 | if len(v) == 0 { 131 | s.Where(sql.False()) 132 | return 133 | } 134 | s.Where(sql.In(s.C(FieldPassword), v...)) 135 | }) 136 | } 137 | 138 | // PasswordNotIn applies the NotIn predicate on the "password" field. 139 | func PasswordNotIn(vs ...string) predicate.User { 140 | v := make([]interface{}, len(vs)) 141 | for i := range v { 142 | v[i] = vs[i] 143 | } 144 | return predicate.User(func(s *sql.Selector) { 145 | // if not arguments were provided, append the FALSE constants, 146 | // since we can't apply "IN ()". This will make this predicate falsy. 147 | if len(v) == 0 { 148 | s.Where(sql.False()) 149 | return 150 | } 151 | s.Where(sql.NotIn(s.C(FieldPassword), v...)) 152 | }) 153 | } 154 | 155 | // PasswordGT applies the GT predicate on the "password" field. 156 | func PasswordGT(v string) predicate.User { 157 | return predicate.User(func(s *sql.Selector) { 158 | s.Where(sql.GT(s.C(FieldPassword), v)) 159 | }) 160 | } 161 | 162 | // PasswordGTE applies the GTE predicate on the "password" field. 163 | func PasswordGTE(v string) predicate.User { 164 | return predicate.User(func(s *sql.Selector) { 165 | s.Where(sql.GTE(s.C(FieldPassword), v)) 166 | }) 167 | } 168 | 169 | // PasswordLT applies the LT predicate on the "password" field. 170 | func PasswordLT(v string) predicate.User { 171 | return predicate.User(func(s *sql.Selector) { 172 | s.Where(sql.LT(s.C(FieldPassword), v)) 173 | }) 174 | } 175 | 176 | // PasswordLTE applies the LTE predicate on the "password" field. 177 | func PasswordLTE(v string) predicate.User { 178 | return predicate.User(func(s *sql.Selector) { 179 | s.Where(sql.LTE(s.C(FieldPassword), v)) 180 | }) 181 | } 182 | 183 | // PasswordContains applies the Contains predicate on the "password" field. 184 | func PasswordContains(v string) predicate.User { 185 | return predicate.User(func(s *sql.Selector) { 186 | s.Where(sql.Contains(s.C(FieldPassword), v)) 187 | }) 188 | } 189 | 190 | // PasswordHasPrefix applies the HasPrefix predicate on the "password" field. 191 | func PasswordHasPrefix(v string) predicate.User { 192 | return predicate.User(func(s *sql.Selector) { 193 | s.Where(sql.HasPrefix(s.C(FieldPassword), v)) 194 | }) 195 | } 196 | 197 | // PasswordHasSuffix applies the HasSuffix predicate on the "password" field. 198 | func PasswordHasSuffix(v string) predicate.User { 199 | return predicate.User(func(s *sql.Selector) { 200 | s.Where(sql.HasSuffix(s.C(FieldPassword), v)) 201 | }) 202 | } 203 | 204 | // PasswordEqualFold applies the EqualFold predicate on the "password" field. 205 | func PasswordEqualFold(v string) predicate.User { 206 | return predicate.User(func(s *sql.Selector) { 207 | s.Where(sql.EqualFold(s.C(FieldPassword), v)) 208 | }) 209 | } 210 | 211 | // PasswordContainsFold applies the ContainsFold predicate on the "password" field. 212 | func PasswordContainsFold(v string) predicate.User { 213 | return predicate.User(func(s *sql.Selector) { 214 | s.Where(sql.ContainsFold(s.C(FieldPassword), v)) 215 | }) 216 | } 217 | 218 | // NameEQ applies the EQ predicate on the "name" field. 219 | func NameEQ(v string) predicate.User { 220 | return predicate.User(func(s *sql.Selector) { 221 | s.Where(sql.EQ(s.C(FieldName), v)) 222 | }) 223 | } 224 | 225 | // NameNEQ applies the NEQ predicate on the "name" field. 226 | func NameNEQ(v string) predicate.User { 227 | return predicate.User(func(s *sql.Selector) { 228 | s.Where(sql.NEQ(s.C(FieldName), v)) 229 | }) 230 | } 231 | 232 | // NameIn applies the In predicate on the "name" field. 233 | func NameIn(vs ...string) predicate.User { 234 | v := make([]interface{}, len(vs)) 235 | for i := range v { 236 | v[i] = vs[i] 237 | } 238 | return predicate.User(func(s *sql.Selector) { 239 | // if not arguments were provided, append the FALSE constants, 240 | // since we can't apply "IN ()". This will make this predicate falsy. 241 | if len(v) == 0 { 242 | s.Where(sql.False()) 243 | return 244 | } 245 | s.Where(sql.In(s.C(FieldName), v...)) 246 | }) 247 | } 248 | 249 | // NameNotIn applies the NotIn predicate on the "name" field. 250 | func NameNotIn(vs ...string) predicate.User { 251 | v := make([]interface{}, len(vs)) 252 | for i := range v { 253 | v[i] = vs[i] 254 | } 255 | return predicate.User(func(s *sql.Selector) { 256 | // if not arguments were provided, append the FALSE constants, 257 | // since we can't apply "IN ()". This will make this predicate falsy. 258 | if len(v) == 0 { 259 | s.Where(sql.False()) 260 | return 261 | } 262 | s.Where(sql.NotIn(s.C(FieldName), v...)) 263 | }) 264 | } 265 | 266 | // NameGT applies the GT predicate on the "name" field. 267 | func NameGT(v string) predicate.User { 268 | return predicate.User(func(s *sql.Selector) { 269 | s.Where(sql.GT(s.C(FieldName), v)) 270 | }) 271 | } 272 | 273 | // NameGTE applies the GTE predicate on the "name" field. 274 | func NameGTE(v string) predicate.User { 275 | return predicate.User(func(s *sql.Selector) { 276 | s.Where(sql.GTE(s.C(FieldName), v)) 277 | }) 278 | } 279 | 280 | // NameLT applies the LT predicate on the "name" field. 281 | func NameLT(v string) predicate.User { 282 | return predicate.User(func(s *sql.Selector) { 283 | s.Where(sql.LT(s.C(FieldName), v)) 284 | }) 285 | } 286 | 287 | // NameLTE applies the LTE predicate on the "name" field. 288 | func NameLTE(v string) predicate.User { 289 | return predicate.User(func(s *sql.Selector) { 290 | s.Where(sql.LTE(s.C(FieldName), v)) 291 | }) 292 | } 293 | 294 | // NameContains applies the Contains predicate on the "name" field. 295 | func NameContains(v string) predicate.User { 296 | return predicate.User(func(s *sql.Selector) { 297 | s.Where(sql.Contains(s.C(FieldName), v)) 298 | }) 299 | } 300 | 301 | // NameHasPrefix applies the HasPrefix predicate on the "name" field. 302 | func NameHasPrefix(v string) predicate.User { 303 | return predicate.User(func(s *sql.Selector) { 304 | s.Where(sql.HasPrefix(s.C(FieldName), v)) 305 | }) 306 | } 307 | 308 | // NameHasSuffix applies the HasSuffix predicate on the "name" field. 309 | func NameHasSuffix(v string) predicate.User { 310 | return predicate.User(func(s *sql.Selector) { 311 | s.Where(sql.HasSuffix(s.C(FieldName), v)) 312 | }) 313 | } 314 | 315 | // NameEqualFold applies the EqualFold predicate on the "name" field. 316 | func NameEqualFold(v string) predicate.User { 317 | return predicate.User(func(s *sql.Selector) { 318 | s.Where(sql.EqualFold(s.C(FieldName), v)) 319 | }) 320 | } 321 | 322 | // NameContainsFold applies the ContainsFold predicate on the "name" field. 323 | func NameContainsFold(v string) predicate.User { 324 | return predicate.User(func(s *sql.Selector) { 325 | s.Where(sql.ContainsFold(s.C(FieldName), v)) 326 | }) 327 | } 328 | 329 | // And groups predicates with the AND operator between them. 330 | func And(predicates ...predicate.User) predicate.User { 331 | return predicate.User(func(s *sql.Selector) { 332 | s1 := s.Clone().SetP(nil) 333 | for _, p := range predicates { 334 | p(s1) 335 | } 336 | s.Where(s1.P()) 337 | }) 338 | } 339 | 340 | // Or groups predicates with the OR operator between them. 341 | func Or(predicates ...predicate.User) predicate.User { 342 | return predicate.User(func(s *sql.Selector) { 343 | s1 := s.Clone().SetP(nil) 344 | for i, p := range predicates { 345 | if i > 0 { 346 | s1.Or() 347 | } 348 | p(s1) 349 | } 350 | s.Where(s1.P()) 351 | }) 352 | } 353 | 354 | // Not applies the not operator on the given predicate. 355 | func Not(p predicate.User) predicate.User { 356 | return predicate.User(func(s *sql.Selector) { 357 | p(s.Not()) 358 | }) 359 | } 360 | -------------------------------------------------------------------------------- /testcode/ent/user_create.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | "errors" 8 | "fmt" 9 | 10 | "entgo.io/ent/dialect/sql/sqlgraph" 11 | "entgo.io/ent/schema/field" 12 | "github.com/umi0410/how-to-backend-in-go/testcode/ent/user" 13 | ) 14 | 15 | // UserCreate is the builder for creating a User entity. 16 | type UserCreate struct { 17 | config 18 | mutation *UserMutation 19 | hooks []Hook 20 | } 21 | 22 | // SetPassword sets the "password" field. 23 | func (uc *UserCreate) SetPassword(s string) *UserCreate { 24 | uc.mutation.SetPassword(s) 25 | return uc 26 | } 27 | 28 | // SetName sets the "name" field. 29 | func (uc *UserCreate) SetName(s string) *UserCreate { 30 | uc.mutation.SetName(s) 31 | return uc 32 | } 33 | 34 | // SetID sets the "id" field. 35 | func (uc *UserCreate) SetID(s string) *UserCreate { 36 | uc.mutation.SetID(s) 37 | return uc 38 | } 39 | 40 | // Mutation returns the UserMutation object of the builder. 41 | func (uc *UserCreate) Mutation() *UserMutation { 42 | return uc.mutation 43 | } 44 | 45 | // Save creates the User in the database. 46 | func (uc *UserCreate) Save(ctx context.Context) (*User, error) { 47 | var ( 48 | err error 49 | node *User 50 | ) 51 | if len(uc.hooks) == 0 { 52 | if err = uc.check(); err != nil { 53 | return nil, err 54 | } 55 | node, err = uc.sqlSave(ctx) 56 | } else { 57 | var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { 58 | mutation, ok := m.(*UserMutation) 59 | if !ok { 60 | return nil, fmt.Errorf("unexpected mutation type %T", m) 61 | } 62 | if err = uc.check(); err != nil { 63 | return nil, err 64 | } 65 | uc.mutation = mutation 66 | node, err = uc.sqlSave(ctx) 67 | mutation.done = true 68 | return node, err 69 | }) 70 | for i := len(uc.hooks) - 1; i >= 0; i-- { 71 | mut = uc.hooks[i](mut) 72 | } 73 | if _, err := mut.Mutate(ctx, uc.mutation); err != nil { 74 | return nil, err 75 | } 76 | } 77 | return node, err 78 | } 79 | 80 | // SaveX calls Save and panics if Save returns an error. 81 | func (uc *UserCreate) SaveX(ctx context.Context) *User { 82 | v, err := uc.Save(ctx) 83 | if err != nil { 84 | panic(err) 85 | } 86 | return v 87 | } 88 | 89 | // check runs all checks and user-defined validators on the builder. 90 | func (uc *UserCreate) check() error { 91 | if _, ok := uc.mutation.Password(); !ok { 92 | return &ValidationError{Name: "password", err: errors.New("ent: missing required field \"password\"")} 93 | } 94 | if _, ok := uc.mutation.Name(); !ok { 95 | return &ValidationError{Name: "name", err: errors.New("ent: missing required field \"name\"")} 96 | } 97 | return nil 98 | } 99 | 100 | func (uc *UserCreate) sqlSave(ctx context.Context) (*User, error) { 101 | _node, _spec := uc.createSpec() 102 | if err := sqlgraph.CreateNode(ctx, uc.driver, _spec); err != nil { 103 | if cerr, ok := isSQLConstraintError(err); ok { 104 | err = cerr 105 | } 106 | return nil, err 107 | } 108 | return _node, nil 109 | } 110 | 111 | func (uc *UserCreate) createSpec() (*User, *sqlgraph.CreateSpec) { 112 | var ( 113 | _node = &User{config: uc.config} 114 | _spec = &sqlgraph.CreateSpec{ 115 | Table: user.Table, 116 | ID: &sqlgraph.FieldSpec{ 117 | Type: field.TypeString, 118 | Column: user.FieldID, 119 | }, 120 | } 121 | ) 122 | if id, ok := uc.mutation.ID(); ok { 123 | _node.ID = id 124 | _spec.ID.Value = id 125 | } 126 | if value, ok := uc.mutation.Password(); ok { 127 | _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ 128 | Type: field.TypeString, 129 | Value: value, 130 | Column: user.FieldPassword, 131 | }) 132 | _node.Password = value 133 | } 134 | if value, ok := uc.mutation.Name(); ok { 135 | _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ 136 | Type: field.TypeString, 137 | Value: value, 138 | Column: user.FieldName, 139 | }) 140 | _node.Name = value 141 | } 142 | return _node, _spec 143 | } 144 | 145 | // UserCreateBulk is the builder for creating many User entities in bulk. 146 | type UserCreateBulk struct { 147 | config 148 | builders []*UserCreate 149 | } 150 | 151 | // Save creates the User entities in the database. 152 | func (ucb *UserCreateBulk) Save(ctx context.Context) ([]*User, error) { 153 | specs := make([]*sqlgraph.CreateSpec, len(ucb.builders)) 154 | nodes := make([]*User, len(ucb.builders)) 155 | mutators := make([]Mutator, len(ucb.builders)) 156 | for i := range ucb.builders { 157 | func(i int, root context.Context) { 158 | builder := ucb.builders[i] 159 | var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { 160 | mutation, ok := m.(*UserMutation) 161 | if !ok { 162 | return nil, fmt.Errorf("unexpected mutation type %T", m) 163 | } 164 | if err := builder.check(); err != nil { 165 | return nil, err 166 | } 167 | builder.mutation = mutation 168 | nodes[i], specs[i] = builder.createSpec() 169 | var err error 170 | if i < len(mutators)-1 { 171 | _, err = mutators[i+1].Mutate(root, ucb.builders[i+1].mutation) 172 | } else { 173 | // Invoke the actual operation on the latest mutation in the chain. 174 | if err = sqlgraph.BatchCreate(ctx, ucb.driver, &sqlgraph.BatchCreateSpec{Nodes: specs}); err != nil { 175 | if cerr, ok := isSQLConstraintError(err); ok { 176 | err = cerr 177 | } 178 | } 179 | } 180 | mutation.done = true 181 | if err != nil { 182 | return nil, err 183 | } 184 | return nodes[i], nil 185 | }) 186 | for i := len(builder.hooks) - 1; i >= 0; i-- { 187 | mut = builder.hooks[i](mut) 188 | } 189 | mutators[i] = mut 190 | }(i, ctx) 191 | } 192 | if len(mutators) > 0 { 193 | if _, err := mutators[0].Mutate(ctx, ucb.builders[0].mutation); err != nil { 194 | return nil, err 195 | } 196 | } 197 | return nodes, nil 198 | } 199 | 200 | // SaveX is like Save, but panics if an error occurs. 201 | func (ucb *UserCreateBulk) SaveX(ctx context.Context) []*User { 202 | v, err := ucb.Save(ctx) 203 | if err != nil { 204 | panic(err) 205 | } 206 | return v 207 | } 208 | -------------------------------------------------------------------------------- /testcode/ent/user_delete.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | 9 | "entgo.io/ent/dialect/sql" 10 | "entgo.io/ent/dialect/sql/sqlgraph" 11 | "entgo.io/ent/schema/field" 12 | "github.com/umi0410/how-to-backend-in-go/testcode/ent/predicate" 13 | "github.com/umi0410/how-to-backend-in-go/testcode/ent/user" 14 | ) 15 | 16 | // UserDelete is the builder for deleting a User entity. 17 | type UserDelete struct { 18 | config 19 | hooks []Hook 20 | mutation *UserMutation 21 | } 22 | 23 | // Where adds a new predicate to the UserDelete builder. 24 | func (ud *UserDelete) Where(ps ...predicate.User) *UserDelete { 25 | ud.mutation.predicates = append(ud.mutation.predicates, ps...) 26 | return ud 27 | } 28 | 29 | // Exec executes the deletion query and returns how many vertices were deleted. 30 | func (ud *UserDelete) Exec(ctx context.Context) (int, error) { 31 | var ( 32 | err error 33 | affected int 34 | ) 35 | if len(ud.hooks) == 0 { 36 | affected, err = ud.sqlExec(ctx) 37 | } else { 38 | var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { 39 | mutation, ok := m.(*UserMutation) 40 | if !ok { 41 | return nil, fmt.Errorf("unexpected mutation type %T", m) 42 | } 43 | ud.mutation = mutation 44 | affected, err = ud.sqlExec(ctx) 45 | mutation.done = true 46 | return affected, err 47 | }) 48 | for i := len(ud.hooks) - 1; i >= 0; i-- { 49 | mut = ud.hooks[i](mut) 50 | } 51 | if _, err := mut.Mutate(ctx, ud.mutation); err != nil { 52 | return 0, err 53 | } 54 | } 55 | return affected, err 56 | } 57 | 58 | // ExecX is like Exec, but panics if an error occurs. 59 | func (ud *UserDelete) ExecX(ctx context.Context) int { 60 | n, err := ud.Exec(ctx) 61 | if err != nil { 62 | panic(err) 63 | } 64 | return n 65 | } 66 | 67 | func (ud *UserDelete) sqlExec(ctx context.Context) (int, error) { 68 | _spec := &sqlgraph.DeleteSpec{ 69 | Node: &sqlgraph.NodeSpec{ 70 | Table: user.Table, 71 | ID: &sqlgraph.FieldSpec{ 72 | Type: field.TypeString, 73 | Column: user.FieldID, 74 | }, 75 | }, 76 | } 77 | if ps := ud.mutation.predicates; len(ps) > 0 { 78 | _spec.Predicate = func(selector *sql.Selector) { 79 | for i := range ps { 80 | ps[i](selector) 81 | } 82 | } 83 | } 84 | return sqlgraph.DeleteNodes(ctx, ud.driver, _spec) 85 | } 86 | 87 | // UserDeleteOne is the builder for deleting a single User entity. 88 | type UserDeleteOne struct { 89 | ud *UserDelete 90 | } 91 | 92 | // Exec executes the deletion query. 93 | func (udo *UserDeleteOne) Exec(ctx context.Context) error { 94 | n, err := udo.ud.Exec(ctx) 95 | switch { 96 | case err != nil: 97 | return err 98 | case n == 0: 99 | return &NotFoundError{user.Label} 100 | default: 101 | return nil 102 | } 103 | } 104 | 105 | // ExecX is like Exec, but panics if an error occurs. 106 | func (udo *UserDeleteOne) ExecX(ctx context.Context) { 107 | udo.ud.ExecX(ctx) 108 | } 109 | -------------------------------------------------------------------------------- /testcode/ent/user_update.go: -------------------------------------------------------------------------------- 1 | // Code generated by entc, DO NOT EDIT. 2 | 3 | package ent 4 | 5 | import ( 6 | "context" 7 | "fmt" 8 | 9 | "entgo.io/ent/dialect/sql" 10 | "entgo.io/ent/dialect/sql/sqlgraph" 11 | "entgo.io/ent/schema/field" 12 | "github.com/umi0410/how-to-backend-in-go/testcode/ent/predicate" 13 | "github.com/umi0410/how-to-backend-in-go/testcode/ent/user" 14 | ) 15 | 16 | // UserUpdate is the builder for updating User entities. 17 | type UserUpdate struct { 18 | config 19 | hooks []Hook 20 | mutation *UserMutation 21 | } 22 | 23 | // Where adds a new predicate for the UserUpdate builder. 24 | func (uu *UserUpdate) Where(ps ...predicate.User) *UserUpdate { 25 | uu.mutation.predicates = append(uu.mutation.predicates, ps...) 26 | return uu 27 | } 28 | 29 | // SetPassword sets the "password" field. 30 | func (uu *UserUpdate) SetPassword(s string) *UserUpdate { 31 | uu.mutation.SetPassword(s) 32 | return uu 33 | } 34 | 35 | // SetName sets the "name" field. 36 | func (uu *UserUpdate) SetName(s string) *UserUpdate { 37 | uu.mutation.SetName(s) 38 | return uu 39 | } 40 | 41 | // Mutation returns the UserMutation object of the builder. 42 | func (uu *UserUpdate) Mutation() *UserMutation { 43 | return uu.mutation 44 | } 45 | 46 | // Save executes the query and returns the number of nodes affected by the update operation. 47 | func (uu *UserUpdate) Save(ctx context.Context) (int, error) { 48 | var ( 49 | err error 50 | affected int 51 | ) 52 | if len(uu.hooks) == 0 { 53 | affected, err = uu.sqlSave(ctx) 54 | } else { 55 | var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { 56 | mutation, ok := m.(*UserMutation) 57 | if !ok { 58 | return nil, fmt.Errorf("unexpected mutation type %T", m) 59 | } 60 | uu.mutation = mutation 61 | affected, err = uu.sqlSave(ctx) 62 | mutation.done = true 63 | return affected, err 64 | }) 65 | for i := len(uu.hooks) - 1; i >= 0; i-- { 66 | mut = uu.hooks[i](mut) 67 | } 68 | if _, err := mut.Mutate(ctx, uu.mutation); err != nil { 69 | return 0, err 70 | } 71 | } 72 | return affected, err 73 | } 74 | 75 | // SaveX is like Save, but panics if an error occurs. 76 | func (uu *UserUpdate) SaveX(ctx context.Context) int { 77 | affected, err := uu.Save(ctx) 78 | if err != nil { 79 | panic(err) 80 | } 81 | return affected 82 | } 83 | 84 | // Exec executes the query. 85 | func (uu *UserUpdate) Exec(ctx context.Context) error { 86 | _, err := uu.Save(ctx) 87 | return err 88 | } 89 | 90 | // ExecX is like Exec, but panics if an error occurs. 91 | func (uu *UserUpdate) ExecX(ctx context.Context) { 92 | if err := uu.Exec(ctx); err != nil { 93 | panic(err) 94 | } 95 | } 96 | 97 | func (uu *UserUpdate) sqlSave(ctx context.Context) (n int, err error) { 98 | _spec := &sqlgraph.UpdateSpec{ 99 | Node: &sqlgraph.NodeSpec{ 100 | Table: user.Table, 101 | Columns: user.Columns, 102 | ID: &sqlgraph.FieldSpec{ 103 | Type: field.TypeString, 104 | Column: user.FieldID, 105 | }, 106 | }, 107 | } 108 | if ps := uu.mutation.predicates; len(ps) > 0 { 109 | _spec.Predicate = func(selector *sql.Selector) { 110 | for i := range ps { 111 | ps[i](selector) 112 | } 113 | } 114 | } 115 | if value, ok := uu.mutation.Password(); ok { 116 | _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ 117 | Type: field.TypeString, 118 | Value: value, 119 | Column: user.FieldPassword, 120 | }) 121 | } 122 | if value, ok := uu.mutation.Name(); ok { 123 | _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ 124 | Type: field.TypeString, 125 | Value: value, 126 | Column: user.FieldName, 127 | }) 128 | } 129 | if n, err = sqlgraph.UpdateNodes(ctx, uu.driver, _spec); err != nil { 130 | if _, ok := err.(*sqlgraph.NotFoundError); ok { 131 | err = &NotFoundError{user.Label} 132 | } else if cerr, ok := isSQLConstraintError(err); ok { 133 | err = cerr 134 | } 135 | return 0, err 136 | } 137 | return n, nil 138 | } 139 | 140 | // UserUpdateOne is the builder for updating a single User entity. 141 | type UserUpdateOne struct { 142 | config 143 | fields []string 144 | hooks []Hook 145 | mutation *UserMutation 146 | } 147 | 148 | // SetPassword sets the "password" field. 149 | func (uuo *UserUpdateOne) SetPassword(s string) *UserUpdateOne { 150 | uuo.mutation.SetPassword(s) 151 | return uuo 152 | } 153 | 154 | // SetName sets the "name" field. 155 | func (uuo *UserUpdateOne) SetName(s string) *UserUpdateOne { 156 | uuo.mutation.SetName(s) 157 | return uuo 158 | } 159 | 160 | // Mutation returns the UserMutation object of the builder. 161 | func (uuo *UserUpdateOne) Mutation() *UserMutation { 162 | return uuo.mutation 163 | } 164 | 165 | // Select allows selecting one or more fields (columns) of the returned entity. 166 | // The default is selecting all fields defined in the entity schema. 167 | func (uuo *UserUpdateOne) Select(field string, fields ...string) *UserUpdateOne { 168 | uuo.fields = append([]string{field}, fields...) 169 | return uuo 170 | } 171 | 172 | // Save executes the query and returns the updated User entity. 173 | func (uuo *UserUpdateOne) Save(ctx context.Context) (*User, error) { 174 | var ( 175 | err error 176 | node *User 177 | ) 178 | if len(uuo.hooks) == 0 { 179 | node, err = uuo.sqlSave(ctx) 180 | } else { 181 | var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { 182 | mutation, ok := m.(*UserMutation) 183 | if !ok { 184 | return nil, fmt.Errorf("unexpected mutation type %T", m) 185 | } 186 | uuo.mutation = mutation 187 | node, err = uuo.sqlSave(ctx) 188 | mutation.done = true 189 | return node, err 190 | }) 191 | for i := len(uuo.hooks) - 1; i >= 0; i-- { 192 | mut = uuo.hooks[i](mut) 193 | } 194 | if _, err := mut.Mutate(ctx, uuo.mutation); err != nil { 195 | return nil, err 196 | } 197 | } 198 | return node, err 199 | } 200 | 201 | // SaveX is like Save, but panics if an error occurs. 202 | func (uuo *UserUpdateOne) SaveX(ctx context.Context) *User { 203 | node, err := uuo.Save(ctx) 204 | if err != nil { 205 | panic(err) 206 | } 207 | return node 208 | } 209 | 210 | // Exec executes the query on the entity. 211 | func (uuo *UserUpdateOne) Exec(ctx context.Context) error { 212 | _, err := uuo.Save(ctx) 213 | return err 214 | } 215 | 216 | // ExecX is like Exec, but panics if an error occurs. 217 | func (uuo *UserUpdateOne) ExecX(ctx context.Context) { 218 | if err := uuo.Exec(ctx); err != nil { 219 | panic(err) 220 | } 221 | } 222 | 223 | func (uuo *UserUpdateOne) sqlSave(ctx context.Context) (_node *User, err error) { 224 | _spec := &sqlgraph.UpdateSpec{ 225 | Node: &sqlgraph.NodeSpec{ 226 | Table: user.Table, 227 | Columns: user.Columns, 228 | ID: &sqlgraph.FieldSpec{ 229 | Type: field.TypeString, 230 | Column: user.FieldID, 231 | }, 232 | }, 233 | } 234 | id, ok := uuo.mutation.ID() 235 | if !ok { 236 | return nil, &ValidationError{Name: "ID", err: fmt.Errorf("missing User.ID for update")} 237 | } 238 | _spec.Node.ID.Value = id 239 | if fields := uuo.fields; len(fields) > 0 { 240 | _spec.Node.Columns = make([]string, 0, len(fields)) 241 | _spec.Node.Columns = append(_spec.Node.Columns, user.FieldID) 242 | for _, f := range fields { 243 | if !user.ValidColumn(f) { 244 | return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} 245 | } 246 | if f != user.FieldID { 247 | _spec.Node.Columns = append(_spec.Node.Columns, f) 248 | } 249 | } 250 | } 251 | if ps := uuo.mutation.predicates; len(ps) > 0 { 252 | _spec.Predicate = func(selector *sql.Selector) { 253 | for i := range ps { 254 | ps[i](selector) 255 | } 256 | } 257 | } 258 | if value, ok := uuo.mutation.Password(); ok { 259 | _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ 260 | Type: field.TypeString, 261 | Value: value, 262 | Column: user.FieldPassword, 263 | }) 264 | } 265 | if value, ok := uuo.mutation.Name(); ok { 266 | _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ 267 | Type: field.TypeString, 268 | Value: value, 269 | Column: user.FieldName, 270 | }) 271 | } 272 | _node = &User{config: uuo.config} 273 | _spec.Assign = _node.assignValues 274 | _spec.ScanValues = _node.scanValues 275 | if err = sqlgraph.UpdateNode(ctx, uuo.driver, _spec); err != nil { 276 | if _, ok := err.(*sqlgraph.NotFoundError); ok { 277 | err = &NotFoundError{user.Label} 278 | } else if cerr, ok := isSQLConstraintError(err); ok { 279 | err = cerr 280 | } 281 | return nil, err 282 | } 283 | return _node, nil 284 | } 285 | -------------------------------------------------------------------------------- /testcode/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/umi0410/how-to-backend-in-go/testcode 2 | 3 | go 1.16 4 | 5 | require ( 6 | entgo.io/ent v0.8.0 7 | github.com/golang/mock v1.6.0 8 | github.com/mattn/go-sqlite3 v1.14.8 9 | github.com/pkg/errors v0.9.1 10 | github.com/sirupsen/logrus v1.8.1 11 | github.com/stretchr/testify v1.7.0 12 | ) 13 | -------------------------------------------------------------------------------- /testcode/gomock.go: -------------------------------------------------------------------------------- 1 | // Code generated by MockGen. DO NOT EDIT. 2 | // Source: repository.go 3 | 4 | // Package main is a generated GoMock package. 5 | package main 6 | 7 | import ( 8 | reflect "reflect" 9 | 10 | gomock "github.com/golang/mock/gomock" 11 | ent "github.com/umi0410/how-to-backend-in-go/testcode/ent" 12 | ) 13 | 14 | // GomockRepository is a mock of UserRepository interface. 15 | type GomockRepository struct { 16 | ctrl *gomock.Controller 17 | recorder *GomockRepositoryMockRecorder 18 | } 19 | 20 | // GomockRepositoryMockRecorder is the mock recorder for GomockRepository. 21 | type GomockRepositoryMockRecorder struct { 22 | mock *GomockRepository 23 | } 24 | 25 | // NewGomockRepository creates a new mock instance. 26 | func NewGomockRepository(ctrl *gomock.Controller) *GomockRepository { 27 | mock := &GomockRepository{ctrl: ctrl} 28 | mock.recorder = &GomockRepositoryMockRecorder{mock} 29 | return mock 30 | } 31 | 32 | // EXPECT returns an object that allows the caller to indicate expected use. 33 | func (m *GomockRepository) EXPECT() *GomockRepositoryMockRecorder { 34 | return m.recorder 35 | } 36 | 37 | // Create mocks base method. 38 | func (m *GomockRepository) Create(input *UserCreateInput) (*ent.User, error) { 39 | m.ctrl.T.Helper() 40 | ret := m.ctrl.Call(m, "Create", input) 41 | ret0, _ := ret[0].(*ent.User) 42 | ret1, _ := ret[1].(error) 43 | return ret0, ret1 44 | } 45 | 46 | // Create indicates an expected call of Create. 47 | func (mr *GomockRepositoryMockRecorder) Create(input interface{}) *gomock.Call { 48 | mr.mock.ctrl.T.Helper() 49 | return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*GomockRepository)(nil).Create), input) 50 | } 51 | -------------------------------------------------------------------------------- /testcode/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | _ "github.com/mattn/go-sqlite3" 6 | log "github.com/sirupsen/logrus" 7 | "github.com/umi0410/how-to-backend-in-go/testcode/ent" 8 | "github.com/umi0410/how-to-backend-in-go/testcode/ent/migrate" 9 | ) 10 | 11 | func main(){ 12 | client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1") 13 | if err != nil { 14 | log.Fatal(err) 15 | } 16 | defer client.Close() 17 | if err := client.Schema.Create( 18 | context.TODO(), 19 | migrate.WithDropIndex(true), 20 | migrate.WithDropColumn(true), 21 | ); err != nil { 22 | log.Fatalf("failed creating schema resources: %v", err) 23 | } 24 | 25 | userRepository := NewUserRepository(client.User) 26 | log.Info(userRepository) 27 | 28 | } 29 | -------------------------------------------------------------------------------- /testcode/mock.sh: -------------------------------------------------------------------------------- 1 | # 이런 식으로 각각의 code generation tool 이용 가능 2 | mockery --dir . --name "UserRepository" --inpackage 3 | mockgen -package main -destination gomock.go -source repository.go --mock_names UserRepository=GomockRepository -------------------------------------------------------------------------------- /testcode/mock_UserRepository.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v0.0.0-dev. DO NOT EDIT. 2 | 3 | package main 4 | 5 | import ( 6 | mock "github.com/stretchr/testify/mock" 7 | ent "github.com/umi0410/how-to-backend-in-go/testcode/ent" 8 | ) 9 | 10 | // MockUserRepository is an autogenerated mock type for the UserRepository type 11 | type MockUserRepository struct { 12 | mock.Mock 13 | } 14 | 15 | // Create provides a mock function with given fields: input 16 | func (_m *MockUserRepository) Create(input *UserCreateInput) (*ent.User, error) { 17 | ret := _m.Called(input) 18 | 19 | var r0 *ent.User 20 | if rf, ok := ret.Get(0).(func(*UserCreateInput) *ent.User); ok { 21 | r0 = rf(input) 22 | } else { 23 | if ret.Get(0) != nil { 24 | r0 = ret.Get(0).(*ent.User) 25 | } 26 | } 27 | 28 | var r1 error 29 | if rf, ok := ret.Get(1).(func(*UserCreateInput) error); ok { 30 | r1 = rf(input) 31 | } else { 32 | r1 = ret.Error(1) 33 | } 34 | 35 | return r0, r1 36 | } 37 | -------------------------------------------------------------------------------- /testcode/repository.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "github.com/umi0410/how-to-backend-in-go/testcode/ent" 6 | ) 7 | 8 | type UserRepository interface{ 9 | Create(input *UserCreateInput) (*ent.User, error) 10 | } 11 | 12 | 13 | func NewUserRepository(userClient *ent.UserClient) UserRepository{ 14 | return &UserRepositoryImpl{ 15 | Client: userClient, 16 | } 17 | } 18 | 19 | type UserRepositoryImpl struct{ 20 | Client *ent.UserClient 21 | } 22 | 23 | func (u *UserRepositoryImpl) Create(input *UserCreateInput) (*ent.User, error) { 24 | user, err := u.Client.Create(). 25 | SetID(input.ID). 26 | SetPassword(input.Password). 27 | SetName(input.Name). 28 | Save(context.TODO()) 29 | return user, err 30 | } 31 | -------------------------------------------------------------------------------- /testcode/service.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/pkg/errors" 5 | "github.com/umi0410/how-to-backend-in-go/testcode/ent" 6 | ) 7 | 8 | var ( 9 | ErrInvalidValue = errors.New("올바르지 않은 값입니다") 10 | ErrInvalidUserID = errors.Wrap(ErrInvalidValue, "유저 ID가 조건을 만족하지 않습니다") 11 | ErrInvalidPassword = errors.Wrap(ErrInvalidValue, "비밀번호는 6자리 이상이어야합니다") 12 | ErrInvalidUserName = errors.Wrap(ErrInvalidValue, "유저 이름이 조건을 만족하지 않습니다") 13 | ) 14 | 15 | // 편의상 서비스는 interface를 이용하지 않고 16 | // 단순히 struct를 이용 17 | type UserService struct{ 18 | // UserRepository는 interface이기 때문에 mocking 될 수 있는 등 좀 더 유연하다. 19 | userRepository UserRepository 20 | } 21 | 22 | // 의존성 주입 형태 - Good 23 | func NewUserService(userRepository UserRepository) *UserService{ 24 | return &UserService{ 25 | userRepository: userRepository, 26 | } 27 | } 28 | 29 | // 의존성을 주입하지 않는 형태 - Bad 30 | func NewUserServiceWithoutInjection(client *ent.UserClient) *UserService{ 31 | return &UserService{ 32 | userRepository: NewUserRepository(client), 33 | } 34 | } 35 | 36 | func (s *UserService) Create(input *UserCreateInput) (*ent.User, error){ 37 | // 도메인/비즈니스 룰, 로직 구현, 조합 38 | 39 | // 유저 ID에 대한 룰 40 | if len(input.ID) < 6 || 20 < len(input.ID) { 41 | return nil, ErrInvalidUserID 42 | } 43 | 44 | // 유저 이름에 대한 룰 45 | if len(input.Name) < 2 || 20 < len(input.Name) { 46 | return nil, ErrInvalidUserName 47 | } 48 | 49 | // 유저 패스워드에 대한 룰 50 | if len(input.Password) < 6 { 51 | return nil, ErrInvalidPassword 52 | } 53 | 54 | // Data Access Layer를 호출 55 | // 이 부분은 추상화된 Interface에 의존하기 때문에 Mocking될 수 있다. 56 | user, err := s.userRepository.Create(input) 57 | if err != nil { 58 | return nil, err 59 | } 60 | 61 | return user, nil 62 | } -------------------------------------------------------------------------------- /testcode/service_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/golang/mock/gomock" 5 | log "github.com/sirupsen/logrus" 6 | "github.com/stretchr/testify/assert" 7 | "github.com/stretchr/testify/mock" 8 | "github.com/umi0410/how-to-backend-in-go/testcode/ent" 9 | "testing" 10 | ) 11 | 12 | type ManualMockUserRepository struct{} 13 | 14 | func (m *ManualMockUserRepository) Create(input *UserCreateInput) (*ent.User, error) { 15 | log.Info("직접 Mocking. Args: ", input) 16 | return &ent.User{}, nil 17 | } 18 | 19 | func TestUserService_CreateWithManualMock(t *testing.T){ 20 | s := NewUserService(new(ManualMockUserRepository)) 21 | 22 | _, err := s.Create(&UserCreateInput{ID: "jinsu_umi", Name: "Jinsu Park", Password: "123123123"}) 23 | // 이런 식으로 로그를 통해 하나 하나 테스트 결과를 확인하는 것이 아니라 24 | //t.Log("에러가 존재하지 않아야합니다.") 25 | //t.Log("err == nil 인지 확인하십시오. err == nil: " , err == nil) 26 | // assert를 이용해 자동으로 성공/실패를 판단하십시오. 27 | assert.NoError(t, err) 28 | } 29 | 30 | func TestUserService_CreateWithMockery(t *testing.T){ 31 | mockUserRepository := &MockUserRepository{} 32 | // method를 문자열 자체로 설정해야해서 safe하지 않음. 33 | mockUserRepository.On("Create", mock.Anything).Run(func(args mock.Arguments) { 34 | t.Log("testify/mock과 mockery를 이용한 Mocking. Args: ", args.Get(0)) 35 | }).Return(&ent.User{}, nil) 36 | // 해당 이름의 유저가 있는지 확인 37 | s := NewUserService(mockUserRepository) 38 | 39 | _, err := s.Create(&UserCreateInput{ID: "jinsu_umi", Name: "Jinsu Park", Password: "123123123"}) 40 | assert.NoError(t, err) 41 | } 42 | 43 | func TestUserService_CreateWithMockgen(t *testing.T){ 44 | // gomock controller을 만들고 Finish 시켜주는 등의 불편함 존재. 45 | ctrl := gomock.NewController(t) 46 | defer ctrl.Finish() 47 | 48 | mockUserRepository := NewGomockRepository(ctrl) 49 | // 원래의 type을 기반으로 method가 safe하게 제공됨. 50 | mockUserRepository.EXPECT().Create(gomock.Any()).DoAndReturn( 51 | func(input *UserCreateInput) (*ent.User, error) { 52 | t.Log("Gomock을 이용한 Mocking. Args: ", input) 53 | return &ent.User{}, nil 54 | }) 55 | // 해당 이름의 유저가 있는지 확인 56 | s := NewUserService(mockUserRepository) 57 | 58 | _, err := s.Create(&UserCreateInput{ID: "jinsu_umi", Name: "Jinsu Park", Password: "123123123"}) 59 | assert.NoError(t, err) 60 | } 61 | 62 | func TestUserService_유저_생성(t *testing.T){ 63 | // repository mocking 64 | ctrl := gomock.NewController(t) 65 | defer ctrl.Finish() 66 | 67 | mockUserRepository := NewGomockRepository(ctrl) 68 | // 원래의 type을 기반으로 method가 safe하게 제공됨. 69 | mockUserRepository.EXPECT().Create(gomock.Any()).DoAndReturn( 70 | func(input *UserCreateInput) (*ent.User, error) { 71 | t.Log("Gomock을 이용한 Mocking. Args: ", input) 72 | return &ent.User{}, nil 73 | }) 74 | // 해당 이름의 유저가 있는지 확인 75 | s := NewUserService(mockUserRepository) 76 | 77 | t.Run("성공", func(t *testing.T) { 78 | _, err := s.Create(&UserCreateInput{ID: "jinsu_umi", Name: "Jinsu Park", Password: "123123123"}) 79 | assert.NoError(t, err) 80 | }) 81 | 82 | t.Run("에러) 너무 짧은 아이디", func(t *testing.T) { 83 | _, err := s.Create(&UserCreateInput{ID: "short", Name: "Jinsu Park", Password: "123123123"}) 84 | assert.ErrorIs(t, err, ErrInvalidUserID) 85 | assert.ErrorIs(t, err, ErrInvalidValue) 86 | }) 87 | 88 | t.Run("에러) 너무 긴 이름", func(t *testing.T) { 89 | _, err := s.Create(&UserCreateInput{ID: "jinsu_umi", Name: "니노막시무스 카이저 쏘제 쏘냐도르앤 스파르타 죽지 않아 나는 죽지않아 오오오오 나는 카이저 쏘제", Password: "123123123"}) 90 | assert.ErrorIs(t, err, ErrInvalidUserName) 91 | assert.ErrorIs(t, err, ErrInvalidValue) 92 | }) 93 | 94 | t.Run("에러) 너무 짧은 비밀번호들", func(t *testing.T) { 95 | errorPasswords := []string{ 96 | "123", 97 | "abc", 98 | "a1b2", 99 | "asd", 100 | } 101 | for _, errorPassword := range errorPasswords { 102 | t.Run("테스트 케이스) " + errorPassword, func(t *testing.T) { 103 | _, err := s.Create(&UserCreateInput{ID: "jinsu_umi", Name: "Jinsu Park", Password: errorPassword}) 104 | assert.ErrorIs(t, err, ErrInvalidPassword) 105 | assert.ErrorIs(t, err, ErrInvalidValue) 106 | }) 107 | } 108 | }) 109 | } -------------------------------------------------------------------------------- /testcode/test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | -------------------------------------------------------------------------------- /webapp/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/umi0410/how-to-backend-in-go/webapp 2 | 3 | go 1.16 4 | 5 | require github.com/gofiber/fiber/v2 v2.17.0 6 | -------------------------------------------------------------------------------- /webapp/go.sum: -------------------------------------------------------------------------------- 1 | github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E= 2 | github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= 3 | github.com/gofiber/fiber/v2 v2.17.0 h1:qP3PkGUbBB0i9iQh5E057XI1yO5CZigUxZhyUFYAFoM= 4 | github.com/gofiber/fiber/v2 v2.17.0/go.mod h1:iftruuHGkRYGEXVISmdD7HTYWyfS2Bh+Dkfq4n/1Owg= 5 | github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= 6 | github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8= 7 | github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= 8 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 9 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= 10 | github.com/valyala/fasthttp v1.26.0 h1:k5Tooi31zPG/g8yS6o2RffRO2C9B9Kah9SY8j/S7058= 11 | github.com/valyala/fasthttp v1.26.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= 12 | github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= 13 | github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= 14 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= 15 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 16 | golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 17 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 18 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 19 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E= 20 | golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 21 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 22 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 23 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 24 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 25 | -------------------------------------------------------------------------------- /webapp/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "github.com/gofiber/fiber/v2" 7 | "log" 8 | "net/http" 9 | ) 10 | 11 | var ( 12 | framework string 13 | port = flag.Int("p", 8888, "서버가 Listen할 port 번호를 입력해주세요.") 14 | ) 15 | 16 | func init() { 17 | flag.Parse() 18 | if len(flag.Args()) != 1 { 19 | log.Fatal("하나의 인자를 전달해 framework를 정의해주세요. (e.g. http, echo, fiber)") 20 | } 21 | framework = flag.Arg(0) 22 | } 23 | func main() { 24 | switch framework { 25 | case "http": 26 | RunNewHttpServer() 27 | case "fiber": 28 | RunNewFiberServer() 29 | default: 30 | log.Fatal("지원하지 않는 framework 입니다.") 31 | } 32 | } 33 | 34 | func RunNewHttpServer() { 35 | addr := fmt.Sprintf(":%d", *port) 36 | log.Printf("Server is listening %d", *port) 37 | http.HandleFunc("/ping", func(w http.ResponseWriter, req *http.Request) { 38 | if _, err := w.Write([]byte("PingPong by net/http\n")); err != nil { 39 | log.Print(err) 40 | } 41 | }) 42 | 43 | if err := http.ListenAndServe(addr, nil); err != nil { 44 | log.Print(err) 45 | } 46 | } 47 | 48 | func RunNewFiberServer() { 49 | addr := fmt.Sprintf(":%d", *port) 50 | app := fiber.New() 51 | 52 | app.Get("/ping", func(c *fiber.Ctx) error { 53 | return c.SendString("Pingpong by fiber\n") 54 | }) 55 | log.Printf("Server is listening %d", *port) 56 | if err := app.Listen(addr); err != nil { 57 | log.Print(err) 58 | } 59 | } 60 | --------------------------------------------------------------------------------