diff --git a/.gitignore b/.gitignore index 24e9d9f..fc1d909 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ meonzi +.idea +go.sum \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..92533a4 --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +ifndef binary + binary=debug +endif + +test: + go test -v -cover -covermode=atomic ./... + +mod-download: + go mod download + +generate: + bash ./generate.sh + +build: + go build -o ${binary} . + +unittest: + go test -short ./... + +clean: + if [ -f ${binary} ] ; then rm ${binary} ; fi + +lint-prepare: + @echo "Installing golangci-lint" + curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s latest + +lint: + ./bin/golangci-lint run \ + --exclude-use-default=false \ + --enable=golint \ + --enable=gocyclo \ + --enable=goconst \ + --enable=unconvert \ + ./... \ No newline at end of file diff --git a/account/api/controller.go b/account/api/controller.go deleted file mode 100644 index ae86570..0000000 --- a/account/api/controller.go +++ /dev/null @@ -1,76 +0,0 @@ -package api - -import ( - "encoding/json" - "github/four-servings/meonzi/account/app/command" - "github/four-servings/meonzi/account/app/query" - "net/http" -) - -type ( - // Controller http controller - Controller interface { - Handle(w http.ResponseWriter, r *http.Request) - } - - controllerImplement struct { - commandBus command.Bus - queryBus query.Bus - } - - createAccountBody struct { - Name string - } -) - -// NewController create controller instance -func NewController(commandBus command.Bus, queryBus query.Bus) Controller { - return &controllerImplement{commandBus, queryBus} -} - -// Handle handle http request -func (c *controllerImplement) Handle(w http.ResponseWriter, r *http.Request) { - c.branchByMethod(w, r) -} - -func (c *controllerImplement) branchByMethod(w http.ResponseWriter, r *http.Request) { - switch r.Method { - case "POST": - c.handlePOST(w, r) - return - case "GET": - c.handleGET(w, r) - return - default: - c.handleNotAllowedMethod(w, r) - return - } -} - -func (c *controllerImplement) handlePOST(w http.ResponseWriter, r *http.Request) { - decoder := json.NewDecoder(r.Body) - decoder.DisallowUnknownFields() - - body := createAccountBody{} - if decoder.Decode(&body) != nil { - http.Error(w, "can not parse body", http.StatusBadRequest) - return - } - - c.commandBus.Handle(&command.CreateAccount{Name: body.Name}) - w.WriteHeader(http.StatusCreated) -} - -func (c *controllerImplement) handleGET(w http.ResponseWriter, r *http.Request) { - if r.URL.Query().Get("name") != "" { - result := c.queryBus.Handle(&query.Find{Name: r.URL.Query().Get("name")}) - w.Header().Set("Content-type", "application/json") - json.NewEncoder(w).Encode(result) - return - } - w.WriteHeader(http.StatusNotFound) -} - -func (c *controllerImplement) handleNotAllowedMethod(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusMethodNotAllowed) -} diff --git a/account/app/command.go b/account/app/command.go new file mode 100644 index 0000000..f0bb741 --- /dev/null +++ b/account/app/command.go @@ -0,0 +1,107 @@ +package app + +import ( + "context" + "errors" + "github/four-servings/meonzi/account/domain" + "github/four-servings/meonzi/pipe" + "time" + + "golang.org/x/sync/errgroup" + + "github.com/google/uuid" + log "github.com/sirupsen/logrus" +) + +type ( + CommandBus interface { + pipe.Bus + } + + commandHandler struct { + domain.AccountRepository + domain.SocialService + } +) + +func NewCommandBus(accountRepo domain.AccountRepository, socialService domain.SocialService, timeout time.Duration) (bus CommandBus) { + handler := commandHandler{accountRepo, socialService} + bus = pipe.NewBusWithTimeout(timeout) + + g, _ := errgroup.WithContext(context.Background()) + g.Go(func() error { + return bus.RegistryHandler(RegisterAccountCommand{}, handler.RegisterAccountHandle) + }) + g.Go(func() error { + return bus.RegistryHandler(DeregisterAccountCommand{}, handler.DeregisterAccountHandle) + }) + err := g.Wait() + if err != nil { + panic(err) + } + + return +} + +type RegisterAccountCommand struct { + Name string + Token string + Provider domain.AuthProvider +} + +func (ch *commandHandler) RegisterAccountHandle(ctx context.Context, command RegisterAccountCommand) (err error) { + id, err := ch.AccountRepository.FindNewID(ctx) + if err != nil { + log.WithError(err).Error("Can not get new account ID") + return + } + + thirdUser, err := ch.SocialService.GetUser(ctx, command.Provider, command.Token) + if err != nil { + log.WithError(err).Errorf("Can not fetch %s user", command.Provider) + return + } + + exists, _ := ch.AccountRepository.FindByProviderAndSocialID(ctx, command.Provider, command.Token) + if exists != nil { + err = errors.New("exists account") + log.Error("Account is exists") + return + } + + account := domain.NewAccount(domain.NewAccountOptions{ + ID: id, + Name: command.Name, + AuthProvider: thirdUser.AuthProvider(), + SocialID: thirdUser.ID(), + }) + + account, err = ch.AccountRepository.Save(ctx, account) + if err != nil { + log.WithError(err).Error("Can not save account") + return + } + + return nil +} + +type DeregisterAccountCommand struct { + ID uuid.UUID +} + +//TODO refactor, error handling on http handler +func (ch *commandHandler) DeregisterAccountHandle(ctx context.Context, command DeregisterAccountCommand) error { + account, err := ch.AccountRepository.FindByID(ctx, command.ID) + if err != nil { + log.WithError(err).Error("Can not found account") + } + + account.Deregister() + + account, err = ch.AccountRepository.Save(ctx, account) + if err != nil { + log.WithError(err).Error("Can not save account") + } + + return nil +} \ No newline at end of file diff --git a/account/app/command/bus.go b/account/app/command/bus.go deleted file mode 100644 index d90b187..0000000 --- a/account/app/command/bus.go +++ /dev/null @@ -1,34 +0,0 @@ -package command - -import ( - "errors" - "github/four-servings/meonzi/account/domain" -) - -type ( - // Bus command bus interface - Bus interface { - Handle(command interface{}) - } - - // bustImplement command bus implement - bustImplement struct { - createAccountHandler createAccountHandler - } -) - -// NewBus create command bus instance -func NewBus(repository domain.AccountRepository) Bus { - createAccountHandler := newCreateAccountHandler(repository) - return &bustImplement{createAccountHandler} -} - -// Handle handle given command -func (b *bustImplement) Handle(givenCommand interface{}) { - switch givenCommand := givenCommand.(type) { - case *CreateAccount: - b.createAccountHandler.handle(givenCommand) - default: - panic(errors.New("invalid command")) - } -} diff --git a/account/app/command/create.go b/account/app/command/create.go deleted file mode 100644 index 179b20f..0000000 --- a/account/app/command/create.go +++ /dev/null @@ -1,30 +0,0 @@ -package command - -import ( - "github/four-servings/meonzi/account/domain" -) - -type ( - // CreateAccount create account command - CreateAccount struct { - Name string - } - - createAccountHandler interface { - handle(command *CreateAccount) - } - - createAccountHandlerImplement struct { - repository domain.AccountRepository - } -) - -func newCreateAccountHandler(repository domain.AccountRepository) createAccountHandler { - return &createAccountHandlerImplement{repository} -} - -func (h *createAccountHandlerImplement) handle(command *CreateAccount) { - id := h.repository.FindNewID() - account := domain.NewAccount(id, command.Name) - h.repository.Save(account) -} diff --git a/account/app/event.go b/account/app/event.go new file mode 100644 index 0000000..b5ce0c2 --- /dev/null +++ b/account/app/event.go @@ -0,0 +1,13 @@ +package app + +import ( + "github/four-servings/meonzi/pipe" +) + +type EventPublisher interface { + pipe.PubSub +} + +func NewEventPublisher() EventPublisher { + return pipe.NewPubSub() +} diff --git a/account/app/query/bus.go b/account/app/query/bus.go deleted file mode 100644 index a692e86..0000000 --- a/account/app/query/bus.go +++ /dev/null @@ -1,36 +0,0 @@ -package query - -import ( - "errors" -) - -type ( - // Bus query bus interface - Bus interface { - Handle(query interface{}) interface{} - } - - busImplement struct { - findByIDHandler findByIDHandler - findHandler findHandler - } -) - -// NewBus create bus instance -func NewBus(query AccountQuery) Bus { - findByIDHandler := newFindByIDHandler(query) - findHandler := newFindHandler(query) - return &busImplement{findByIDHandler, findHandler} -} - -// Handle handle given query -func (b *busImplement) Handle(givenQuery interface{}) interface{} { - switch givenQuery := givenQuery.(type) { - case *FindByID: - return b.findByIDHandler.handle(givenQuery) - case *Find: - return b.findHandler.handle(givenQuery) - default: - panic(errors.New("invalid query")) - } -} diff --git a/account/app/query/find.go b/account/app/query/find.go deleted file mode 100644 index b94587b..0000000 --- a/account/app/query/find.go +++ /dev/null @@ -1,36 +0,0 @@ -package query - -type ( - // Find find account - Find struct { - Name string - } - - // FindResult found account result - FindResult []struct { - Name string `json:"name"` - } - - findHandler interface { - handle(query *Find) FindResult - } - - findHandlerImplement struct { - query AccountQuery - } -) - -func newFindHandler(query AccountQuery) findHandler { - return &findHandlerImplement{query} -} - -func (h *findHandlerImplement) handle(query *Find) FindResult { - accounts := h.query.FindByName(query.Name) - result := FindResult{} - for _, account := range accounts { - result = append(result, struct { - Name string "json:\"name\"" - }{account.Name}) - } - return result -} diff --git a/account/app/query/findById.go b/account/app/query/findById.go deleted file mode 100644 index 4ee2cb7..0000000 --- a/account/app/query/findById.go +++ /dev/null @@ -1,34 +0,0 @@ -package query - -type ( - // FindByID find account by id - FindByID struct { - ID string - } - - // FindByIDResult query result for findByID - FindByIDResult struct { - ID string - Name string - } - - findByIDHandler interface { - handle(query *FindByID) FindByIDResult - } - - findByIDHandlerImplement struct { - query AccountQuery - } -) - -func newFindByIDHandler(query AccountQuery) findByIDHandler { - return &findByIDHandlerImplement{query} -} - -func (h *findByIDHandlerImplement) handle(query *FindByID) FindByIDResult { - account := h.query.FindByID(query.ID) - return struct { - ID string - Name string - }{account.ID, account.Name} -} diff --git a/account/app/query/query.go b/account/app/query/query.go deleted file mode 100644 index 4647c05..0000000 --- a/account/app/query/query.go +++ /dev/null @@ -1,20 +0,0 @@ -package query - -type ( - // Account account document query result - Account struct { - ID string - Name string - } - - // Accounts account collection query result - Accounts []struct { - Name string - } - - // AccountQuery account query from data - AccountQuery interface { - FindByID(id string) Account - FindByName(name string) Accounts - } -) diff --git a/account/domain/account.go b/account/domain/account.go index a621d51..fa711ef 100644 --- a/account/domain/account.go +++ b/account/domain/account.go @@ -1,89 +1,127 @@ package domain -import "time" - -type ( - //Account account interface - Account interface { - ID() string - Name() string - LastAccessedAt() time.Time - CreatedAt() time.Time - UpdatedAt() time.Time - DeletedAt() *time.Time - } +import ( + "context" + "github/four-servings/meonzi/util/pointer" + "time" - // AccountImplement account model - AccountImplement struct { - id string - name string - lastAccessedAt time.Time - createdAt time.Time - updatedAt time.Time - deletedAt *time.Time - } + "github.com/google/uuid" +) - // AnemicAccount anemic account model - AnemicAccount struct { - ID string - Name string - LastAccessedAt time.Time - CreatedAt time.Time - UpdatedAt time.Time - DeletedAt *time.Time +// NewAccount create new account object +func NewAccount(options NewAccountOptions) Account { + return &accountImpl{ + AccountData: AccountData{ + ID: options.ID, + Name: options.Name, + AuthProvider: options.AuthProvider, + SocialID: options.SocialID, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + DeletedAt: nil, + }, } +} - // AccountRepository account repository - AccountRepository interface { - Save(account Account) - FindNewID() string - FindByID(id string) Account +// ReconstituteAccount reconstitute account object +func ReconstituteAccount(options ReconstituteAccountOptions) Account { + return &accountImpl{ + AccountData: AccountData{ + ID: options.ID, + Name: options.Name, + AuthProvider: options.AuthProvider, + SocialID: options.SocialID, + CreatedAt: options.CreatedAt, + UpdatedAt: options.UpdatedAt, + DeletedAt: options.DeletedAt, + }, } -) +} -// NewAccount create account instance -func NewAccount(id, name string) Account { - now := time.Now() - return &AccountImplement{id, name, now, now, now, nil} +// NewAccountOptions account option for create new account +type NewAccountOptions struct { + ID uuid.UUID + Name string + AuthProvider AuthProvider + SocialID string } -// ID account id -func (account *AccountImplement) ID() string { - return account.id +// ReconstituteAccountOptions reconstitute option for reconstitute account +type ReconstituteAccountOptions struct { + ID uuid.UUID + Name string + AuthProvider AuthProvider + SocialID string + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt *time.Time } -// Name account name -func (account *AccountImplement) Name() string { - return account.name +type AccountData struct { + ID uuid.UUID + Name string + AuthProvider AuthProvider + SocialID string + CreatedAt time.Time + UpdatedAt time.Time + DeletedAt *time.Time } -// LastAccessedAt account last access time -func (account *AccountImplement) LastAccessedAt() time.Time { - return account.lastAccessedAt +// Account account domain object interface +type Account interface { + Events() []interface{} + Apply(interface{}) + Deregister() + Data() AccountData } -// CreatedAt account created time -func (account *AccountImplement) CreatedAt() time.Time { - return account.createdAt +// Deregister deregister account +func (a *accountImpl) Deregister() { + a.DeletedAt = pointer.Time(time.Now()) } -// UpdatedAt account last updated time -func (account *AccountImplement) UpdatedAt() time.Time { - return account.updatedAt +// Events get applied account events +func (a *accountImpl) Events() (events []interface{}) { + events = append(events, a.events...) + return } -// DeletedAt account deleted time -func (account *AccountImplement) DeletedAt() *time.Time { - return account.deletedAt +// Apply apply event to account +func (a *accountImpl) Apply(event interface{}) { + a.events = append(a.events, event) } -// ToRichModel create rich account model from anemic -func (anemic *AnemicAccount) ToRichModel() Account { - id := anemic.ID - name := anemic.Name - lastAccessedAt := anemic.LastAccessedAt - createdAt := anemic.CreatedAt - updatedAt := anemic.UpdatedAt - deletedAt := anemic.DeletedAt - return &AccountImplement{id, name, lastAccessedAt, createdAt, updatedAt, deletedAt} +func (a *accountImpl) Data() AccountData { + data := a.AccountData + + //deep copy + if data.DeletedAt != nil { + data.DeletedAt = pointer.Time(*data.DeletedAt) + } + + return data +} + +const ( + // KakaoServiceProviderKey key for AuthProvider value + KakaoServiceProviderKey = AuthProvider("KAKAO") + + // GoogleServiceProviderKey key for AuthProvider value + GoogleServiceProviderKey = AuthProvider("GOOGLE") +) + +type accountImpl struct { + AccountData + events []interface{} +} + +// AuthProvider third party service provider +type AuthProvider string + +// AccountRepository account repository +type AccountRepository interface { + Save(ctx context.Context, account Account) (Account, error) + FindByID(ctx context.Context, id uuid.UUID) (Account, error) + FindNewID(ctx context.Context) (uuid.UUID, error) + FindByProviderAndSocialID(ctx context.Context, provider AuthProvider, socialID string) (Account, error) } diff --git a/account/domain/account_test.go b/account/domain/account_test.go deleted file mode 100644 index 636964e..0000000 --- a/account/domain/account_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package domain - -import ( - "testing" - "time" -) - -func TestNewAccount(t *testing.T) { - account := NewAccount("id", "name") - if account.ID() != "id" || account.Name() != "name" { - t.Fail() - } -} - -func TestToRichModel(t *testing.T) { - now := time.Now() - account := AccountImplement{"id", "name", now, now, now, nil} - enemic := AnemicAccount{"id", "name", now, now, now, nil} - - result := enemic.ToRichModel() - - if result.ID() != account.id { - t.Fail() - } - if result.Name() != account.name { - t.Fail() - } - if result.LastAccessedAt() != account.lastAccessedAt { - t.Fail() - } - if result.CreatedAt() != account.createdAt { - t.Fail() - } - if result.UpdatedAt() != account.updatedAt { - t.Fail() - } - if result.DeletedAt() != account.deletedAt { - t.Fail() - } -} diff --git a/account/domain/adapter.go b/account/domain/adapter.go new file mode 100644 index 0000000..dd56942 --- /dev/null +++ b/account/domain/adapter.go @@ -0,0 +1,21 @@ +package domain + +import "context" + +type ( + SocialAdapter interface { + GetUser(ctx context.Context, token string) (ThirdUser, error) + } + + // KakaoAdapter kakao service adapter + KakaoAdapter SocialAdapter + + // GoogleAdapter google service adapter + GoogleAdapter SocialAdapter + + // ThirdUser third party user data + ThirdUser interface { + ID() string + AuthProvider() AuthProvider + } +) diff --git a/account/domain/auth_service.go b/account/domain/auth_service.go new file mode 100644 index 0000000..ff396d0 --- /dev/null +++ b/account/domain/auth_service.go @@ -0,0 +1,25 @@ +package domain + +import ( + "github.com/dgrijalva/jwt-go" + "github.com/google/uuid" +) + + +type AccountSignInClaims struct { + jwt.StandardClaims + AccountId uuid.UUID `json:"accountId"` + //TODO if you need auth scope like acl, RBAC. so you will define auth scope and write code logic + //Scopes []string +} + +type AccountToken struct { + AccessToken string + RefreshToken string +} + +type AuthService interface { + GetToken(account Account) AccountToken + GetAccountByAccessToken(token string) (claims *AccountSignInClaims, err error) + GetAccountByRefreshToken(token string) (claims *AccountSignInClaims, err error) +} diff --git a/account/domain/event.go b/account/domain/event.go new file mode 100644 index 0000000..828e920 --- /dev/null +++ b/account/domain/event.go @@ -0,0 +1,17 @@ +package domain + +type ( + //UserRegisteredEvent struct { + // Id uuid.UUID + // Account ent.Account + //} + // + //UserUpdatedEvent struct { + // Id uuid.UUID + // Account ent.Account + //} + // + //UserRemovedEvent struct { + // Id uuid.UUID + //} +) \ No newline at end of file diff --git a/account/domain/social_service.go b/account/domain/social_service.go new file mode 100644 index 0000000..94d1104 --- /dev/null +++ b/account/domain/social_service.go @@ -0,0 +1,7 @@ +package domain + +import "context" + +type SocialService interface { + GetUser(ctx context.Context, provider AuthProvider, token string) (ThirdUser, error) +} \ No newline at end of file diff --git a/account/infra/adapter_google.go b/account/infra/adapter_google.go new file mode 100644 index 0000000..2dc0e92 --- /dev/null +++ b/account/infra/adapter_google.go @@ -0,0 +1,84 @@ +package infra + +import ( + "context" + "encoding/json" + "fmt" + log "github.com/sirupsen/logrus" + "github/four-servings/meonzi/account/domain" + "net/http" + "net/url" +) + +type ( + googleAdapter struct{} + + googleUserResponse struct { + ID int64 `json:"sub"` + } + + googleUser struct { + id string + } + + googleError struct { + ErrorDescription string `json:"error_description"` + } +) + +func (e googleError) Error() string { + return e.ErrorDescription +} + +func NewGoogleAdapter() domain.GoogleAdapter { + return &googleAdapter{} +} + +func (*googleAdapter) GetUser(ctx context.Context, token string) (user domain.ThirdUser, err error) { + val := make(url.Values) + val.Add("id_token", token) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, + fmt.Sprintf("%s%s?%s", endPoint, "/oauth2/v3/tokeninfo", val.Encode()), nil) + if err != nil { + log.WithError(err).Error("google api request: get token info") + return + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + log.WithError(err).Error("google api response: get token info") + return + } + + defer resp.Body.Close() + decoder := json.NewDecoder(resp.Body) + + var model googleUserResponse + + switch resp.StatusCode { + case http.StatusOK: + err = decoder.Decode(&model) + user = googleUser{id: fmt.Sprint(model.ID)} + default: + var clientError googleError + err = decoder.Decode(&clientError) + if err == nil { + err = clientError + return + } + } + if err != nil { + log.WithError(err).Error("response body json unmarshal failed") + } + + return +} + +func (g googleUser) ID() string { + return g.id +} + +func (g googleUser) AuthProvider() domain.AuthProvider { + return domain.GoogleServiceProviderKey +} diff --git a/account/infra/adapter_kakao.go b/account/infra/adapter_kakao.go new file mode 100644 index 0000000..1af7f82 --- /dev/null +++ b/account/infra/adapter_kakao.go @@ -0,0 +1,88 @@ +package infra + +import ( + "context" + "encoding/json" + "fmt" + "github/four-servings/meonzi/account/domain" + "net/http" + + log "github.com/sirupsen/logrus" +) + +type ( + kakaoAdapter struct{} + + kakaoUserResponse struct { + ID int64 `json:"id"` + } + + kakaoUser struct { + id string + } + + kakaoError struct { + Code int64 `json:"code"` + Message string `json:"msg"` + } +) + +func (e kakaoError) Error() string { + return fmt.Sprintf("code:%d/message:%s", e.Code, e.Message) +} + +const ( + endPoint = "https://kapi.kakao.com" +) + +func NewKakaoAdapter() domain.KakaoAdapter { + return &kakaoAdapter{} +} + +func (k *kakaoAdapter) GetUser(ctx context.Context, token string) (user domain.ThirdUser, err error) { + url := fmt.Sprintf("%s%s", endPoint, "/v2/user/me?secure_resource=true") + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + log.WithError(err).Error("kakao api request: get user info") + return + } + + req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token)) + + resp, err := http.DefaultClient.Do(req) + if err != nil { + log.WithError(err).Error("kakao api response: get user info") + return + } + + defer resp.Body.Close() + decoder := json.NewDecoder(resp.Body) + + var model kakaoUserResponse + + switch resp.StatusCode { + case http.StatusOK: + err = decoder.Decode(&model) + user = kakaoUser{id: fmt.Sprint(model.ID)} + default: + var clientError kakaoError + err = decoder.Decode(&clientError) + if err == nil { + err = clientError + return + } + } + if err != nil { + log.WithError(err).Error("response body json unmarshal failed") + } + + return +} + +func (k kakaoUser) ID() string { + return k.id +} + +func (k kakaoUser) AuthProvider() domain.AuthProvider { + return domain.KakaoServiceProviderKey +} diff --git a/account/infra/auth_service.go b/account/infra/auth_service.go new file mode 100644 index 0000000..34d586f --- /dev/null +++ b/account/infra/auth_service.go @@ -0,0 +1,96 @@ +package infra + +import ( + "fmt" + "github.com/dgrijalva/jwt-go" + "github/four-servings/meonzi/account/domain" + "time" +) + +type authServiceImpl struct { + secretKey []byte + refreshSecretKey []byte + expires time.Duration + refreshExpires time.Duration +} + +func NewAuthService() domain.AuthService { + return &authServiceImpl{ + + //TODO config + secretKey: []byte("access_token_sign"), + refreshSecretKey: []byte("refresh_token_sign"), + expires: time.Hour * 7, + refreshExpires: time.Hour * 24 * 7, + } +} + +func (a *authServiceImpl) GetToken(account domain.Account) (token domain.AccountToken) { + now := time.Now() + claims := a.getAccessClaims(account, now) + refreshClaims := a.getRefreshClaims(account, now) + token.AccessToken, _ = jwt.NewWithClaims(jwt.SigningMethodHS256, claims). + SignedString(a.secretKey) + token.RefreshToken, _ = jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims). + SignedString(a.refreshSecretKey) + return +} + +func (a *authServiceImpl) GetAccountByAccessToken(token string) (claims *domain.AccountSignInClaims, err error) { + claims, err = validateToken(token, a.refreshSecretKey) + //TODO unauthorized error handling + return +} + +func (a *authServiceImpl) GetAccountByRefreshToken(token string) (claims *domain.AccountSignInClaims, err error) { + claims, err = validateToken(token, a.refreshSecretKey) + //TODO unauthorized error handling + return +} + +func (a *authServiceImpl) getAccessClaims(account domain.Account, now time.Time) domain.AccountSignInClaims { + data := account.Data() + return domain.AccountSignInClaims{ + StandardClaims: jwt.StandardClaims{ + //Audience: "", + ExpiresAt: now.Add(a.expires).Unix(), + //Id: "", + IssuedAt: now.Unix(), + Issuer: "self", // TODO refactor, more meaningful than "self" + //NotBefore: 0 + //Subject: "", + }, + AccountId: data.ID, + } +} + +func (a *authServiceImpl) getRefreshClaims(account domain.Account, now time.Time) domain.AccountSignInClaims { + data := account.Data() + return domain.AccountSignInClaims{ + StandardClaims: jwt.StandardClaims{ + //Audience: "", + ExpiresAt: now.Add(a.refreshExpires).Unix(), + //Id: "", + IssuedAt: now.Unix(), + Issuer: "self", // TODO refactor, more meaningful than "self" + //NotBefore: 0 + //Subject: "", + }, + AccountId: data.ID, + } +} + +func validateToken(token string, secretKey []byte) (*domain.AccountSignInClaims, error) { + tk, err := jwt.ParseWithClaims(token, &domain.AccountSignInClaims{}, func(token *jwt.Token) (interface{}, error) { + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) + } + + return secretKey, nil + }) + if err != nil { + return nil, err + } + + return tk.Claims.(*domain.AccountSignInClaims), nil +} diff --git a/account/infra/entity.go b/account/infra/entity.go deleted file mode 100644 index 1140b23..0000000 --- a/account/infra/entity.go +++ /dev/null @@ -1,13 +0,0 @@ -package infra - -import "time" - -// Account account entity -type Account struct { - ID string `gorm:"primary_key"` - Name string `gorm:"not null"` - LastAccessedAt time.Time `gorm:"not null"` - CreatedAt time.Time `gorm:"not null"` - UpdatedAt time.Time `gorm:"not null"` - DeletedAt *time.Time `sql:"index"` -} diff --git a/account/infra/http.go b/account/infra/http.go new file mode 100644 index 0000000..228bedc --- /dev/null +++ b/account/infra/http.go @@ -0,0 +1,64 @@ +package infra + +import ( + "github.com/labstack/echo/v4" + "github/four-servings/meonzi/account/interfaces" + "net/http" +) + +type handler struct { + interfaces.Controller +} + +type Routing func() + +func NewRoute(e *echo.Echo, controller interfaces.Controller) Routing { + return func() { + handler := handler{controller} + e.POST("/account", handler.registerAccount) + e.POST("/auth", ) + } +} + +func (h *handler) registerAccount(ctx echo.Context) error { + var binder struct { + Token string `json:"token"` + Provider string `json:"provider"` + Name string `json:"name"` + } + err := ctx.Bind(&binder) + if err != nil { + return ctx.NoContent(http.StatusBadRequest) + } + + dto := interfaces.RegisterAccountDTO{ + Token: binder.Token, + Name: binder.Name, + Provider: binder.Provider, + } + //TODO error handling + h.Controller.RegisterAccount(dto) + return nil +} + +func (h *handler) getAccessToken(ctx echo.Context) error { + var binder struct { + Token string `json:"token"` + Provider string `json:"provider"` + } + + err := ctx.Bind(&binder) + if err != nil { + return ctx.NoContent(http.StatusBadRequest) + } + + token, err := h.Controller.SignIn(interfaces.SignInAccountDTO{ + Token: binder.Token, + Provider: binder.Provider, + }) + if err != nil { + //TODO error handling + return ctx.NoContent(http.StatusInternalServerError) + } + return ctx.JSON(http.StatusOK, token) +} \ No newline at end of file diff --git a/account/infra/mapper.go b/account/infra/mapper.go deleted file mode 100644 index 2356111..0000000 --- a/account/infra/mapper.go +++ /dev/null @@ -1,21 +0,0 @@ -package infra - -import "github/four-servings/meonzi/account/domain" - -// EntityFromModel create entity from model -func EntityFromModel(model domain.Account) Account { - return Account{model.ID(), model.Name(), model.LastAccessedAt(), model.CreatedAt(), model.UpdatedAt(), model.DeletedAt()} -} - -// ModelFromEntity create model from entity -func ModelFromEntity(entity Account) domain.Account { - anemic := domain.AnemicAccount{ - ID: entity.ID, - Name: entity.Name, - LastAccessedAt: entity.LastAccessedAt, - CreatedAt: entity.CreatedAt, - UpdatedAt: entity.UpdatedAt, - DeletedAt: entity.DeletedAt, - } - return anemic.ToRichModel() -} diff --git a/account/infra/mapper_test.go b/account/infra/mapper_test.go deleted file mode 100644 index 7c91096..0000000 --- a/account/infra/mapper_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package infra - -import ( - "github/four-servings/meonzi/account/domain" - "testing" -) - -func TestEntityFromModel(t *testing.T) { - model := domain.NewAccount("id", "name") - - createdAt := model.CreatedAt() - updatedAt := model.UpdatedAt() - deletedAt := model.DeletedAt() - lastAccessedAt := model.LastAccessedAt() - - entity := Account{"id", "name", lastAccessedAt, createdAt, updatedAt, deletedAt} - - result := EntityFromModel(model) - - if result != entity { - t.Fail() - } -} - -func TestModelFromEntity(t *testing.T) { - model := domain.NewAccount("id", "name") - - lastAccessedAt := model.LastAccessedAt() - createdAt := model.CreatedAt() - updatedAt := model.UpdatedAt() - deletedAt := model.DeletedAt() - - entity := Account{"id", "name", lastAccessedAt, createdAt, updatedAt, deletedAt} - - result := ModelFromEntity(entity) - - if result.ID() != model.ID() { - t.Fail() - } - - if result.Name() != model.Name() { - t.Fail() - } - - if result.LastAccessedAt() != model.LastAccessedAt() { - t.Fail() - } - - if result.CreatedAt() != model.CreatedAt() { - t.Fail() - } - - if result.UpdatedAt() != model.UpdatedAt() { - t.Fail() - } - - if result.DeletedAt() != model.DeletedAt() { - t.Fail() - } -} diff --git a/account/infra/query.go b/account/infra/query.go index 30523d9..ed5eb69 100644 --- a/account/infra/query.go +++ b/account/infra/query.go @@ -1,43 +1,25 @@ package infra import ( - "github/four-servings/meonzi/account/app/query" - "log" - - "gorm.io/gorm" + "github/four-servings/meonzi/ent" + "github/four-servings/meonzi/ent/schema" ) -type accountQueryImplement struct { - db *gorm.DB -} +type ( + GetAccountBySocial struct { + SocialType schema.SocialType + SocialId string + } -// NewQuery create query instance -func NewQuery(db *gorm.DB) query.AccountQuery { - return &accountQueryImplement{db} -} + Query interface { -// FindByID find account by id -func (q *accountQueryImplement) FindByID(id string) query.Account { - entity := Account{} - if err := q.db.Where(&Account{ID: id}).First(&entity).Error; err != nil { - panic(err) } - return struct { - ID string - Name string - }{entity.ID, entity.Name} -} -// FindByName find account by name -func (q *accountQueryImplement) FindByName(name string) query.Accounts { - entities := []Account{} - if err := q.db.Where(&Account{Name: name}).Find(&entities).Error; err != nil { - log.Println(err) - panic(err) - } - result := query.Accounts{} - for _, entity := range entities { - result = append(result, struct{ Name string }{Name: entity.Name}) + queryImpl struct { + cli *ent.AccountClient } - return result +) + +func (q *queryImpl) FindByID(id string) { + // SELECT t.... } diff --git a/account/infra/repository.go b/account/infra/repository.go index cf9b969..7d7b55b 100644 --- a/account/infra/repository.go +++ b/account/infra/repository.go @@ -1,57 +1,121 @@ package infra import ( - "github/four-servings/meonzi/account/domain" - + "context" + "errors" "github.com/google/uuid" - "gorm.io/gorm" + log "github.com/sirupsen/logrus" + "github/four-servings/meonzi/account/domain" + "github/four-servings/meonzi/ent" + "github/four-servings/meonzi/ent/account" + "github/four-servings/meonzi/ent/schema" + "github/four-servings/meonzi/util/arr" ) -type accountRepositoryImplement struct { - db *gorm.DB +type repo struct { + cli *ent.AccountClient } -// NewRepository create repository instance -func NewRepository(db *gorm.DB) domain.AccountRepository { - err := db.AutoMigrate(&Account{}) - if err != nil { - panic(err) - } - return &accountRepositoryImplement{db} + +func NewAccountRepository(cli *ent.AccountClient) domain.AccountRepository { + return &repo{cli} } -// Save insert or update account date -func (r *accountRepositoryImplement) Save(account domain.Account) { - if err := r.db.Save(EntityFromModel(account)).Error; err != nil { - panic(err) +func (r *repo) FindNewID(ctx context.Context) (newId uuid.UUID, err error) { + id := uuid.New() + exists, _ := r.cli.Get(ctx, id) + if exists != nil { + log.Error("account find new id exception") + err = errors.New("account find new id exception") + return } + newId = id + return } -// FindNewID find new id -func (r *accountRepositoryImplement) FindNewID() string { - id, err := uuid.NewUUID() +func (r *repo) Save(ctx context.Context, account domain.Account) (saved domain.Account, err error) { + data := account.Data() + entity, _ := r.cli.Get(ctx, data.ID) + var save func(context.Context) (*ent.Account, error) + if entity != nil { + save = entity.Update(). + SetName(data.Name). + SetNillableDeleteAt(data.DeletedAt).Save + } else { + save = r.cli.Create(). + SetID(data.ID). + SetSocialType(convertAuthProviderToSocialType(data.AuthProvider)). + SetSocialID(data.SocialID). + SetName(data.Name).Save + } + + entity, err = save(ctx) if err != nil { - panic(err) + log.WithError(err).Error("account save exception") + return } + saved = convertEntityToDomain(entity) + return +} - result := r.db.Where(&Account{ID: id.String()}).First(&Account{}) - if result.Error != nil && result.Error.Error() != "record not found" { - panic(result.Error) +func (r *repo) FindByID(ctx context.Context, id uuid.UUID) (res domain.Account, err error) { + acc, err := r.cli.Get(ctx, id) + if err != nil { + log.WithError(err).Error("account find by id exception") + return } - if result.RowsAffected != 0 { - return r.FindNewID() + res = convertEntityToDomain(acc) + return +} + +func (r *repo) FindByProviderAndSocialID(ctx context.Context, provider domain.AuthProvider, socialID string) (res domain.Account, err error) { + acc, err := r.cli.Query(). + Where(account.And( + account.SocialType(convertAuthProviderToSocialType(provider)), + account.SocialID(socialID), + )).First(ctx) + if err != nil { + log.WithFields(log.Fields{ + "args": arr.Flatten(provider, socialID), + }).WithError(err).Error("account get by social exception") + return } - return id.String() + res = convertEntityToDomain(acc) + return } -// FindByID find account by id -func (r *accountRepositoryImplement) FindByID(id string) domain.Account { - account := Account{} - result := r.db.Where(&Account{ID: id}).First(&account) - if result.Error != nil { - panic(result.Error) +func convertAuthProviderToSocialType(provider domain.AuthProvider) schema.SocialType { + switch provider { + case domain.KakaoServiceProviderKey: + return schema.SocialTypeKakao + case domain.GoogleServiceProviderKey: + return schema.SocialTypeGoogle + default: + return schema.SocialTypeUnknown } - return ModelFromEntity(account) } + +func convertEntityToDomain(from *ent.Account) domain.Account { + return domain.ReconstituteAccount(domain.ReconstituteAccountOptions{ + ID: from.ID, + Name: from.Name, + AuthProvider: convertSocialTypeToAuthProvider(from.SocialType), + SocialID: from.SocialID, + CreatedAt: from.CreateAt, + UpdatedAt: from.UpdateAt, + DeletedAt: from.DeleteAt, + }) +} + +func convertSocialTypeToAuthProvider(socialType schema.SocialType) domain.AuthProvider { + switch socialType { + case schema.SocialTypeKakao: + return domain.KakaoServiceProviderKey + case schema.SocialTypeGoogle: + return domain.GoogleServiceProviderKey + default: + return "-" + } +} \ No newline at end of file diff --git a/account/infra/social_service.go b/account/infra/social_service.go new file mode 100644 index 0000000..03909eb --- /dev/null +++ b/account/infra/social_service.go @@ -0,0 +1,39 @@ +package infra + +import ( + "context" + "errors" + "github/four-servings/meonzi/account/domain" +) + +type unknownAdapterImpl struct {} + +var unknownAdapter domain.SocialAdapter = unknownAdapterImpl{} + +func (unknownAdapterImpl) GetUser(_ context.Context, _ string) (domain.ThirdUser, error) { + return nil, errors.New("weird auth provider") +} + +type socialServiceImpl struct { + domain.GoogleAdapter + domain.KakaoAdapter +} + +func NewSocialService(google domain.GoogleAdapter, kakao domain.KakaoAdapter) domain.SocialService { + return &socialServiceImpl{google, kakao} +} + +func (s *socialServiceImpl) GetUser(ctx context.Context, provider domain.AuthProvider, token string) (domain.ThirdUser, error) { + return s.getSocialAdapter(provider).GetUser(ctx, token) +} + +func (s *socialServiceImpl) getSocialAdapter(provider domain.AuthProvider) domain.SocialAdapter { + switch provider { + case domain.GoogleServiceProviderKey: + return s.GoogleAdapter + case domain.KakaoServiceProviderKey: + return s.KakaoAdapter + } + + return unknownAdapter +} \ No newline at end of file diff --git a/account/interfaces/controller.go b/account/interfaces/controller.go new file mode 100644 index 0000000..9bfb1a3 --- /dev/null +++ b/account/interfaces/controller.go @@ -0,0 +1,77 @@ +package interfaces + +import ( + "context" + "errors" + "github.com/go-playground/validator/v10" + log "github.com/sirupsen/logrus" + "github/four-servings/meonzi/account/app" + "github/four-servings/meonzi/account/domain" +) + +type RegisterAccountDTO struct { + Name string `validate:"required,min=2,max=8"` + Token string `validate:"required"` + Provider string `validate:"required,eq=KAKAO|eq=GOOGLE"` +} + +type SignInAccountDTO struct { + Token string `validate:"required"` + Provider string `validate:"required,eq=KAKAO|eq=GOOGLE"` +} + +type Controller interface { + RegisterAccount(dto RegisterAccountDTO) error + SignIn(dto SignInAccountDTO) (domain.AccountToken, error) +} + +type controllerImpl struct { + app.CommandBus + *validator.Validate + domain.AccountRepository + domain.AuthService + domain.SocialService +} + +func NewAccountController(bus app.CommandBus, validator *validator.Validate, + repository domain.AccountRepository, authService domain.AuthService, socialService domain.SocialService) Controller { + return &controllerImpl{bus, validator, repository, authService, socialService} +} + +func (c *controllerImpl) RegisterAccount(dto RegisterAccountDTO) (err error) { + err = c.Validate.Struct(dto) + if err != nil { + //TODO bad request + return + } + return c.CommandBus.Execute(app.RegisterAccountCommand{ + Token: dto.Token, + Name: dto.Name, + Provider: domain.AuthProvider(dto.Provider), + }) +} + + +func (c *controllerImpl) SignIn(dto SignInAccountDTO) (token domain.AccountToken, err error) { + err = c.Validate.Struct(dto) + if err != nil { + //TODO bad request + return + } + + user, err := c.SocialService.GetUser(context.Background(), domain.AuthProvider(dto.Provider), dto.Token) + if err != nil { + log.WithError(err).Errorf("Can not fetch %s user", dto.Provider) + return + } + + account, _ := c.AccountRepository.FindByProviderAndSocialID(context.Background(), user.AuthProvider(), user.ID()) + if account == nil { + err = errors.New("not found account") + log.Error("Can not found account") + return + } + + token = c.AuthService.GetToken(account) + return +} \ No newline at end of file diff --git a/account/main.go b/account/main.go deleted file mode 100644 index af4c058..0000000 --- a/account/main.go +++ /dev/null @@ -1,19 +0,0 @@ -package account - -import ( - "github/four-servings/meonzi/account/api" - "github/four-servings/meonzi/account/app/command" - "github/four-servings/meonzi/account/app/query" - "github/four-servings/meonzi/account/infra" - "github/four-servings/meonzi/setup" - "net/http" -) - -func init() { - dbConnection := setup.GetDatabaseConnection() - commandBus := command.NewBus(infra.NewRepository(dbConnection)) - queryBus := query.NewBus(infra.NewQuery(dbConnection)) - controller := api.NewController(commandBus, queryBus) - - http.HandleFunc("/accounts", controller.Handle) -} diff --git a/app/app.go b/app/app.go new file mode 100644 index 0000000..56e0903 --- /dev/null +++ b/app/app.go @@ -0,0 +1,48 @@ +package app + +import ( + "fmt" + "github.com/google/wire" + "github.com/labstack/echo/v4" + log "github.com/sirupsen/logrus" + "github/four-servings/meonzi/account/infra" + "github/four-servings/meonzi/ent" +) + +var AppSets = wire.NewSet( + GetDBConn, + Routing, + NewApp, + ) + +type setRoute func() + +type App struct { + db *ent.Client + e *echo.Echo +} + +func Routing(r1 infra.Routing) setRoute { + return func() { + r1() + } +} + +func NewApp(db *ent.Client, e *echo.Echo, setRoute setRoute) (app *App) { + app = &App{db, e} + setRoute() + return +} + +func (a *App) Start() { + defer a.close() + e := a.e + e.Start(fmt.Sprintf(":%d", config.Port)) +} + +func (a *App) close() { + err := a.db.Close() + if err != nil { + log.WithError(err).Error("database close exception") + } +} \ No newline at end of file diff --git a/app/env.go b/app/env.go new file mode 100644 index 0000000..2687b41 --- /dev/null +++ b/app/env.go @@ -0,0 +1,48 @@ +package app + +import ( + "fmt" + "github/four-servings/meonzi/di" + "net/url" + "time" + + "github.com/caarlos0/env/v6" +) + +var config struct { + DbUser string `env:"DATABASE_USER" envDefault:"root"` + DbPass string `env:"DATABASE_PASS" envDefault:"qaz456"` + DbHost string `env:"DATABASE_HOST" envDefault:"localhost"` + DbName string `env:"DATABASE_NAME" envDefault:"meonzi"` + DbPort uint16 `env:"DATABASE_PORT" envDefault:"3306"` + + //RedisAddr string `env:"REDIS_ADDR" envDefault:"localhost:6379"` + //RedisPass string `env:"REDIS_PASS"` + //RedisUser string `env:"REDIS_USER" envDefault:"default"` + //RedisDB int `env:"REDIS_DB" envDefault:"10"` + + Port uint16 `env:"PORT" envDefault:"5000"` + IsProduction bool `env:"PRODUCTION" envDefault:"true"` + TimeZone string `env:"TZ" envDefault:"UTC"` + IsDebug bool `env:"DEBUG" envDefault:"true"` +} + +func init() { + err := env.Parse(&config) + if err != nil { + panic(err) + } +} + +func GetDBConn() di.DBConn { + val := url.Values{} + val.Add("parseTime", "true") + val.Add("loc", time.UTC.String()) + return di.DBConn(fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?%s", + config.DbUser, + config.DbPass, + config.DbHost, + config.DbPort, + config.DbName, + val.Encode())) +} \ No newline at end of file diff --git a/config/database.go b/config/database.go deleted file mode 100644 index d7d178f..0000000 --- a/config/database.go +++ /dev/null @@ -1,46 +0,0 @@ -package config - -import "os" - -// Database database config -type Database struct{} - -// User database config -func (d Database) User() string { - if env := os.Getenv("DATABASE_USER"); env != "" { - return env - } - return "root" -} - -// Password database config -func (d Database) Password() string { - if env := os.Getenv("DATABASE_PASSWORD"); env != "" { - return env - } - return "test" -} - -// Host database config -func (d Database) Host() string { - if env := os.Getenv("DATABASE_HOST"); env != "" { - return env - } - return "localhost" -} - -// Port database config -func (d Database) Port() string { - if env := os.Getenv("DATABASE_PORT"); env != "" { - return env - } - return "3306" -} - -// Name database config -func (d Database) Name() string { - if env := os.Getenv("DATABASE_NAME"); env != "" { - return env - } - return "meonzi" -} diff --git a/di/provider.go b/di/provider.go new file mode 100644 index 0000000..20c0087 --- /dev/null +++ b/di/provider.go @@ -0,0 +1,67 @@ +package di + +import ( + "context" + "github.com/go-playground/validator/v10" + "github.com/labstack/echo/v4" + accountApp "github/four-servings/meonzi/account/app" + "github/four-servings/meonzi/account/infra" + "github/four-servings/meonzi/account/interfaces" + "github/four-servings/meonzi/ent" + + _ "github.com/go-sql-driver/mysql" + "github.com/google/wire" +) + +func ProviderDatabase(conn DBConn) *ent.Client { + cli, err := ent.Open("mysql", string(conn)) + if err != nil { + panic(err) + } + if err = cli.Schema.Create(context.Background()); err != nil { + panic(err) + } + + return cli +} + +func ProviderAccountTable(cli *ent.Client) *ent.AccountClient { + return cli.Account +} + +func ProviderEcho() (e *echo.Echo) { + e = echo.New() + return +} + +func ProviderValidator() (v *validator.Validate) { + v = validator.New() + return +} + +var ProviderSets = wire.NewSet( + ProviderDatabase, + ProviderAccountTable, + ProviderEcho, + ProviderValidator, +) + +var InfraSets = wire.NewSet( + infra.NewAccountRepository, + infra.NewKakaoAdapter, + infra.NewGoogleAdapter, + infra.NewSocialService, + infra.NewAuthService, +) + +var CommandBusSets = wire.NewSet( + accountApp.NewCommandBus, +) + +var ControllerSets = wire.NewSet( + interfaces.NewAccountController, +) + +var RouteSets = wire.NewSet( + infra.NewRoute, +) \ No newline at end of file diff --git a/di/scope.go b/di/scope.go new file mode 100644 index 0000000..dfdaed2 --- /dev/null +++ b/di/scope.go @@ -0,0 +1,3 @@ +package di + +type DBConn string diff --git a/ent/account.go b/ent/account.go new file mode 100644 index 0000000..face0b4 --- /dev/null +++ b/ent/account.go @@ -0,0 +1,159 @@ +// Code generated by entc, DO NOT EDIT. + +package ent + +import ( + "fmt" + "github/four-servings/meonzi/ent/account" + "github/four-servings/meonzi/ent/schema" + "strings" + "time" + + "entgo.io/ent/dialect/sql" + "github.com/google/uuid" +) + +// Account is the model entity for the Account schema. +type Account struct { + config `json:"-"` + // ID of the ent. + ID uuid.UUID `json:"id,omitempty"` + // SocialType holds the value of the "social_type" field. + SocialType schema.SocialType `json:"social_type,omitempty"` + // SocialID holds the value of the "social_id" field. + SocialID string `json:"social_id,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` + // CreateAt holds the value of the "create_at" field. + CreateAt time.Time `json:"create_at,omitempty"` + // UpdateAt holds the value of the "update_at" field. + UpdateAt time.Time `json:"update_at,omitempty"` + // DeleteAt holds the value of the "delete_at" field. + DeleteAt *time.Time `json:"delete_at,omitempty"` +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*Account) scanValues(columns []string) ([]interface{}, error) { + values := make([]interface{}, len(columns)) + for i := range columns { + switch columns[i] { + case account.FieldSocialType: + values[i] = &sql.NullInt64{} + case account.FieldSocialID, account.FieldName: + values[i] = &sql.NullString{} + case account.FieldCreateAt, account.FieldUpdateAt, account.FieldDeleteAt: + values[i] = &sql.NullTime{} + case account.FieldID: + values[i] = &uuid.UUID{} + default: + return nil, fmt.Errorf("unexpected column %q for type Account", columns[i]) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the Account fields. +func (a *Account) assignValues(columns []string, values []interface{}) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case account.FieldID: + if value, ok := values[i].(*uuid.UUID); !ok { + return fmt.Errorf("unexpected type %T for field id", values[i]) + } else if value != nil { + a.ID = *value + } + case account.FieldSocialType: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field social_type", values[i]) + } else if value.Valid { + a.SocialType = schema.SocialType(value.Int64) + } + case account.FieldSocialID: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field social_id", values[i]) + } else if value.Valid { + a.SocialID = value.String + } + case account.FieldName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field name", values[i]) + } else if value.Valid { + a.Name = value.String + } + case account.FieldCreateAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field create_at", values[i]) + } else if value.Valid { + a.CreateAt = value.Time + } + case account.FieldUpdateAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field update_at", values[i]) + } else if value.Valid { + a.UpdateAt = value.Time + } + case account.FieldDeleteAt: + if value, ok := values[i].(*sql.NullTime); !ok { + return fmt.Errorf("unexpected type %T for field delete_at", values[i]) + } else if value.Valid { + a.DeleteAt = new(time.Time) + *a.DeleteAt = value.Time + } + } + } + return nil +} + +// Update returns a builder for updating this Account. +// Note that you need to call Account.Unwrap() before calling this method if this Account +// was returned from a transaction, and the transaction was committed or rolled back. +func (a *Account) Update() *AccountUpdateOne { + return (&AccountClient{config: a.config}).UpdateOne(a) +} + +// Unwrap unwraps the Account entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (a *Account) Unwrap() *Account { + tx, ok := a.config.driver.(*txDriver) + if !ok { + panic("ent: Account is not a transactional entity") + } + a.config.driver = tx.drv + return a +} + +// String implements the fmt.Stringer. +func (a *Account) String() string { + var builder strings.Builder + builder.WriteString("Account(") + builder.WriteString(fmt.Sprintf("id=%v", a.ID)) + builder.WriteString(", social_type=") + builder.WriteString(fmt.Sprintf("%v", a.SocialType)) + builder.WriteString(", social_id=") + builder.WriteString(a.SocialID) + builder.WriteString(", name=") + builder.WriteString(a.Name) + builder.WriteString(", create_at=") + builder.WriteString(a.CreateAt.Format(time.ANSIC)) + builder.WriteString(", update_at=") + builder.WriteString(a.UpdateAt.Format(time.ANSIC)) + if v := a.DeleteAt; v != nil { + builder.WriteString(", delete_at=") + builder.WriteString(v.Format(time.ANSIC)) + } + builder.WriteByte(')') + return builder.String() +} + +// Accounts is a parsable slice of Account. +type Accounts []*Account + +func (a Accounts) config(cfg config) { + for _i := range a { + a[_i].config = cfg + } +} diff --git a/ent/account/account.go b/ent/account/account.go new file mode 100644 index 0000000..f9a0198 --- /dev/null +++ b/ent/account/account.go @@ -0,0 +1,63 @@ +// Code generated by entc, DO NOT EDIT. + +package account + +import ( + "time" +) + +const ( + // Label holds the string label denoting the account type in the database. + Label = "account" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldSocialType holds the string denoting the social_type field in the database. + FieldSocialType = "social_type" + // FieldSocialID holds the string denoting the social_id field in the database. + FieldSocialID = "social_id" + // FieldName holds the string denoting the name field in the database. + FieldName = "name" + // FieldCreateAt holds the string denoting the create_at field in the database. + FieldCreateAt = "create_at" + // FieldUpdateAt holds the string denoting the update_at field in the database. + FieldUpdateAt = "update_at" + // FieldDeleteAt holds the string denoting the delete_at field in the database. + FieldDeleteAt = "delete_at" + + // Table holds the table name of the account in the database. + Table = "account" +) + +// Columns holds all SQL columns for account fields. +var Columns = []string{ + FieldID, + FieldSocialType, + FieldSocialID, + FieldName, + FieldCreateAt, + FieldUpdateAt, + FieldDeleteAt, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +var ( + // SocialIDValidator is a validator for the "social_id" field. It is called by the builders before save. + SocialIDValidator func(string) error + // NameValidator is a validator for the "name" field. It is called by the builders before save. + NameValidator func(string) error + // DefaultCreateAt holds the default value on creation for the "create_at" field. + DefaultCreateAt func() time.Time + // DefaultUpdateAt holds the default value on creation for the "update_at" field. + DefaultUpdateAt func() time.Time + // UpdateDefaultUpdateAt holds the default value on update for the "update_at" field. + UpdateDefaultUpdateAt func() time.Time +) diff --git a/ent/account/where.go b/ent/account/where.go new file mode 100644 index 0000000..9efb658 --- /dev/null +++ b/ent/account/where.go @@ -0,0 +1,716 @@ +// Code generated by entc, DO NOT EDIT. + +package account + +import ( + "github/four-servings/meonzi/ent/predicate" + "github/four-servings/meonzi/ent/schema" + "time" + + "entgo.io/ent/dialect/sql" + "github.com/google/uuid" +) + +// ID filters vertices based on their ID field. +func ID(id uuid.UUID) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldID), id)) + }) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id uuid.UUID) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldID), id)) + }) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id uuid.UUID) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldID), id)) + }) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...uuid.UUID) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(ids) == 0 { + s.Where(sql.False()) + return + } + v := make([]interface{}, len(ids)) + for i := range v { + v[i] = ids[i] + } + s.Where(sql.In(s.C(FieldID), v...)) + }) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...uuid.UUID) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(ids) == 0 { + s.Where(sql.False()) + return + } + v := make([]interface{}, len(ids)) + for i := range v { + v[i] = ids[i] + } + s.Where(sql.NotIn(s.C(FieldID), v...)) + }) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id uuid.UUID) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldID), id)) + }) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id uuid.UUID) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldID), id)) + }) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id uuid.UUID) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldID), id)) + }) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id uuid.UUID) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldID), id)) + }) +} + +// SocialType applies equality check predicate on the "social_type" field. It's identical to SocialTypeEQ. +func SocialType(v schema.SocialType) predicate.Account { + vc := uint8(v) + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldSocialType), vc)) + }) +} + +// SocialID applies equality check predicate on the "social_id" field. It's identical to SocialIDEQ. +func SocialID(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldSocialID), v)) + }) +} + +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldName), v)) + }) +} + +// CreateAt applies equality check predicate on the "create_at" field. It's identical to CreateAtEQ. +func CreateAt(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldCreateAt), v)) + }) +} + +// UpdateAt applies equality check predicate on the "update_at" field. It's identical to UpdateAtEQ. +func UpdateAt(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldUpdateAt), v)) + }) +} + +// DeleteAt applies equality check predicate on the "delete_at" field. It's identical to DeleteAtEQ. +func DeleteAt(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldDeleteAt), v)) + }) +} + +// SocialTypeEQ applies the EQ predicate on the "social_type" field. +func SocialTypeEQ(v schema.SocialType) predicate.Account { + vc := uint8(v) + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldSocialType), vc)) + }) +} + +// SocialTypeNEQ applies the NEQ predicate on the "social_type" field. +func SocialTypeNEQ(v schema.SocialType) predicate.Account { + vc := uint8(v) + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldSocialType), vc)) + }) +} + +// SocialTypeIn applies the In predicate on the "social_type" field. +func SocialTypeIn(vs ...schema.SocialType) predicate.Account { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = uint8(vs[i]) + } + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.In(s.C(FieldSocialType), v...)) + }) +} + +// SocialTypeNotIn applies the NotIn predicate on the "social_type" field. +func SocialTypeNotIn(vs ...schema.SocialType) predicate.Account { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = uint8(vs[i]) + } + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.NotIn(s.C(FieldSocialType), v...)) + }) +} + +// SocialTypeGT applies the GT predicate on the "social_type" field. +func SocialTypeGT(v schema.SocialType) predicate.Account { + vc := uint8(v) + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldSocialType), vc)) + }) +} + +// SocialTypeGTE applies the GTE predicate on the "social_type" field. +func SocialTypeGTE(v schema.SocialType) predicate.Account { + vc := uint8(v) + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldSocialType), vc)) + }) +} + +// SocialTypeLT applies the LT predicate on the "social_type" field. +func SocialTypeLT(v schema.SocialType) predicate.Account { + vc := uint8(v) + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldSocialType), vc)) + }) +} + +// SocialTypeLTE applies the LTE predicate on the "social_type" field. +func SocialTypeLTE(v schema.SocialType) predicate.Account { + vc := uint8(v) + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldSocialType), vc)) + }) +} + +// SocialIDEQ applies the EQ predicate on the "social_id" field. +func SocialIDEQ(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldSocialID), v)) + }) +} + +// SocialIDNEQ applies the NEQ predicate on the "social_id" field. +func SocialIDNEQ(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldSocialID), v)) + }) +} + +// SocialIDIn applies the In predicate on the "social_id" field. +func SocialIDIn(vs ...string) predicate.Account { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.In(s.C(FieldSocialID), v...)) + }) +} + +// SocialIDNotIn applies the NotIn predicate on the "social_id" field. +func SocialIDNotIn(vs ...string) predicate.Account { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.NotIn(s.C(FieldSocialID), v...)) + }) +} + +// SocialIDGT applies the GT predicate on the "social_id" field. +func SocialIDGT(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldSocialID), v)) + }) +} + +// SocialIDGTE applies the GTE predicate on the "social_id" field. +func SocialIDGTE(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldSocialID), v)) + }) +} + +// SocialIDLT applies the LT predicate on the "social_id" field. +func SocialIDLT(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldSocialID), v)) + }) +} + +// SocialIDLTE applies the LTE predicate on the "social_id" field. +func SocialIDLTE(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldSocialID), v)) + }) +} + +// SocialIDContains applies the Contains predicate on the "social_id" field. +func SocialIDContains(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.Contains(s.C(FieldSocialID), v)) + }) +} + +// SocialIDHasPrefix applies the HasPrefix predicate on the "social_id" field. +func SocialIDHasPrefix(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.HasPrefix(s.C(FieldSocialID), v)) + }) +} + +// SocialIDHasSuffix applies the HasSuffix predicate on the "social_id" field. +func SocialIDHasSuffix(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.HasSuffix(s.C(FieldSocialID), v)) + }) +} + +// SocialIDEqualFold applies the EqualFold predicate on the "social_id" field. +func SocialIDEqualFold(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EqualFold(s.C(FieldSocialID), v)) + }) +} + +// SocialIDContainsFold applies the ContainsFold predicate on the "social_id" field. +func SocialIDContainsFold(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.ContainsFold(s.C(FieldSocialID), v)) + }) +} + +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldName), v)) + }) +} + +// NameNEQ applies the NEQ predicate on the "name" field. +func NameNEQ(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldName), v)) + }) +} + +// NameIn applies the In predicate on the "name" field. +func NameIn(vs ...string) predicate.Account { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.In(s.C(FieldName), v...)) + }) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.Account { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.NotIn(s.C(FieldName), v...)) + }) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldName), v)) + }) +} + +// NameGTE applies the GTE predicate on the "name" field. +func NameGTE(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldName), v)) + }) +} + +// NameLT applies the LT predicate on the "name" field. +func NameLT(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldName), v)) + }) +} + +// NameLTE applies the LTE predicate on the "name" field. +func NameLTE(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldName), v)) + }) +} + +// NameContains applies the Contains predicate on the "name" field. +func NameContains(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.Contains(s.C(FieldName), v)) + }) +} + +// NameHasPrefix applies the HasPrefix predicate on the "name" field. +func NameHasPrefix(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.HasPrefix(s.C(FieldName), v)) + }) +} + +// NameHasSuffix applies the HasSuffix predicate on the "name" field. +func NameHasSuffix(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.HasSuffix(s.C(FieldName), v)) + }) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EqualFold(s.C(FieldName), v)) + }) +} + +// NameContainsFold applies the ContainsFold predicate on the "name" field. +func NameContainsFold(v string) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.ContainsFold(s.C(FieldName), v)) + }) +} + +// CreateAtEQ applies the EQ predicate on the "create_at" field. +func CreateAtEQ(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldCreateAt), v)) + }) +} + +// CreateAtNEQ applies the NEQ predicate on the "create_at" field. +func CreateAtNEQ(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldCreateAt), v)) + }) +} + +// CreateAtIn applies the In predicate on the "create_at" field. +func CreateAtIn(vs ...time.Time) predicate.Account { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.In(s.C(FieldCreateAt), v...)) + }) +} + +// CreateAtNotIn applies the NotIn predicate on the "create_at" field. +func CreateAtNotIn(vs ...time.Time) predicate.Account { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.NotIn(s.C(FieldCreateAt), v...)) + }) +} + +// CreateAtGT applies the GT predicate on the "create_at" field. +func CreateAtGT(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldCreateAt), v)) + }) +} + +// CreateAtGTE applies the GTE predicate on the "create_at" field. +func CreateAtGTE(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldCreateAt), v)) + }) +} + +// CreateAtLT applies the LT predicate on the "create_at" field. +func CreateAtLT(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldCreateAt), v)) + }) +} + +// CreateAtLTE applies the LTE predicate on the "create_at" field. +func CreateAtLTE(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldCreateAt), v)) + }) +} + +// UpdateAtEQ applies the EQ predicate on the "update_at" field. +func UpdateAtEQ(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldUpdateAt), v)) + }) +} + +// UpdateAtNEQ applies the NEQ predicate on the "update_at" field. +func UpdateAtNEQ(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldUpdateAt), v)) + }) +} + +// UpdateAtIn applies the In predicate on the "update_at" field. +func UpdateAtIn(vs ...time.Time) predicate.Account { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.In(s.C(FieldUpdateAt), v...)) + }) +} + +// UpdateAtNotIn applies the NotIn predicate on the "update_at" field. +func UpdateAtNotIn(vs ...time.Time) predicate.Account { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.NotIn(s.C(FieldUpdateAt), v...)) + }) +} + +// UpdateAtGT applies the GT predicate on the "update_at" field. +func UpdateAtGT(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldUpdateAt), v)) + }) +} + +// UpdateAtGTE applies the GTE predicate on the "update_at" field. +func UpdateAtGTE(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldUpdateAt), v)) + }) +} + +// UpdateAtLT applies the LT predicate on the "update_at" field. +func UpdateAtLT(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldUpdateAt), v)) + }) +} + +// UpdateAtLTE applies the LTE predicate on the "update_at" field. +func UpdateAtLTE(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldUpdateAt), v)) + }) +} + +// DeleteAtEQ applies the EQ predicate on the "delete_at" field. +func DeleteAtEQ(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.EQ(s.C(FieldDeleteAt), v)) + }) +} + +// DeleteAtNEQ applies the NEQ predicate on the "delete_at" field. +func DeleteAtNEQ(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.NEQ(s.C(FieldDeleteAt), v)) + }) +} + +// DeleteAtIn applies the In predicate on the "delete_at" field. +func DeleteAtIn(vs ...time.Time) predicate.Account { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.In(s.C(FieldDeleteAt), v...)) + }) +} + +// DeleteAtNotIn applies the NotIn predicate on the "delete_at" field. +func DeleteAtNotIn(vs ...time.Time) predicate.Account { + v := make([]interface{}, len(vs)) + for i := range v { + v[i] = vs[i] + } + return predicate.Account(func(s *sql.Selector) { + // if not arguments were provided, append the FALSE constants, + // since we can't apply "IN ()". This will make this predicate falsy. + if len(v) == 0 { + s.Where(sql.False()) + return + } + s.Where(sql.NotIn(s.C(FieldDeleteAt), v...)) + }) +} + +// DeleteAtGT applies the GT predicate on the "delete_at" field. +func DeleteAtGT(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GT(s.C(FieldDeleteAt), v)) + }) +} + +// DeleteAtGTE applies the GTE predicate on the "delete_at" field. +func DeleteAtGTE(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.GTE(s.C(FieldDeleteAt), v)) + }) +} + +// DeleteAtLT applies the LT predicate on the "delete_at" field. +func DeleteAtLT(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LT(s.C(FieldDeleteAt), v)) + }) +} + +// DeleteAtLTE applies the LTE predicate on the "delete_at" field. +func DeleteAtLTE(v time.Time) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.LTE(s.C(FieldDeleteAt), v)) + }) +} + +// DeleteAtIsNil applies the IsNil predicate on the "delete_at" field. +func DeleteAtIsNil() predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.IsNull(s.C(FieldDeleteAt))) + }) +} + +// DeleteAtNotNil applies the NotNil predicate on the "delete_at" field. +func DeleteAtNotNil() predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s.Where(sql.NotNull(s.C(FieldDeleteAt))) + }) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.Account) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for _, p := range predicates { + p(s1) + } + s.Where(s1.P()) + }) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.Account) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + s1 := s.Clone().SetP(nil) + for i, p := range predicates { + if i > 0 { + s1.Or() + } + p(s1) + } + s.Where(s1.P()) + }) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.Account) predicate.Account { + return predicate.Account(func(s *sql.Selector) { + p(s.Not()) + }) +} diff --git a/ent/account_create.go b/ent/account_create.go new file mode 100644 index 0000000..f048cd4 --- /dev/null +++ b/ent/account_create.go @@ -0,0 +1,323 @@ +// Code generated by entc, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "github/four-servings/meonzi/ent/account" + "github/four-servings/meonzi/ent/schema" + "time" + + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/google/uuid" +) + +// AccountCreate is the builder for creating a Account entity. +type AccountCreate struct { + config + mutation *AccountMutation + hooks []Hook +} + +// SetSocialType sets the "social_type" field. +func (ac *AccountCreate) SetSocialType(st schema.SocialType) *AccountCreate { + ac.mutation.SetSocialType(st) + return ac +} + +// SetSocialID sets the "social_id" field. +func (ac *AccountCreate) SetSocialID(s string) *AccountCreate { + ac.mutation.SetSocialID(s) + return ac +} + +// SetName sets the "name" field. +func (ac *AccountCreate) SetName(s string) *AccountCreate { + ac.mutation.SetName(s) + return ac +} + +// SetCreateAt sets the "create_at" field. +func (ac *AccountCreate) SetCreateAt(t time.Time) *AccountCreate { + ac.mutation.SetCreateAt(t) + return ac +} + +// SetNillableCreateAt sets the "create_at" field if the given value is not nil. +func (ac *AccountCreate) SetNillableCreateAt(t *time.Time) *AccountCreate { + if t != nil { + ac.SetCreateAt(*t) + } + return ac +} + +// SetUpdateAt sets the "update_at" field. +func (ac *AccountCreate) SetUpdateAt(t time.Time) *AccountCreate { + ac.mutation.SetUpdateAt(t) + return ac +} + +// SetNillableUpdateAt sets the "update_at" field if the given value is not nil. +func (ac *AccountCreate) SetNillableUpdateAt(t *time.Time) *AccountCreate { + if t != nil { + ac.SetUpdateAt(*t) + } + return ac +} + +// SetDeleteAt sets the "delete_at" field. +func (ac *AccountCreate) SetDeleteAt(t time.Time) *AccountCreate { + ac.mutation.SetDeleteAt(t) + return ac +} + +// SetNillableDeleteAt sets the "delete_at" field if the given value is not nil. +func (ac *AccountCreate) SetNillableDeleteAt(t *time.Time) *AccountCreate { + if t != nil { + ac.SetDeleteAt(*t) + } + return ac +} + +// SetID sets the "id" field. +func (ac *AccountCreate) SetID(u uuid.UUID) *AccountCreate { + ac.mutation.SetID(u) + return ac +} + +// Mutation returns the AccountMutation object of the builder. +func (ac *AccountCreate) Mutation() *AccountMutation { + return ac.mutation +} + +// Save creates the Account in the database. +func (ac *AccountCreate) Save(ctx context.Context) (*Account, error) { + var ( + err error + node *Account + ) + ac.defaults() + if len(ac.hooks) == 0 { + if err = ac.check(); err != nil { + return nil, err + } + node, err = ac.sqlSave(ctx) + } else { + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*AccountMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err = ac.check(); err != nil { + return nil, err + } + ac.mutation = mutation + node, err = ac.sqlSave(ctx) + mutation.done = true + return node, err + }) + for i := len(ac.hooks) - 1; i >= 0; i-- { + mut = ac.hooks[i](mut) + } + if _, err := mut.Mutate(ctx, ac.mutation); err != nil { + return nil, err + } + } + return node, err +} + +// SaveX calls Save and panics if Save returns an error. +func (ac *AccountCreate) SaveX(ctx context.Context) *Account { + v, err := ac.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// defaults sets the default values of the builder before save. +func (ac *AccountCreate) defaults() { + if _, ok := ac.mutation.CreateAt(); !ok { + v := account.DefaultCreateAt() + ac.mutation.SetCreateAt(v) + } + if _, ok := ac.mutation.UpdateAt(); !ok { + v := account.DefaultUpdateAt() + ac.mutation.SetUpdateAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (ac *AccountCreate) check() error { + if _, ok := ac.mutation.SocialType(); !ok { + return &ValidationError{Name: "social_type", err: errors.New("ent: missing required field \"social_type\"")} + } + if _, ok := ac.mutation.SocialID(); !ok { + return &ValidationError{Name: "social_id", err: errors.New("ent: missing required field \"social_id\"")} + } + if v, ok := ac.mutation.SocialID(); ok { + if err := account.SocialIDValidator(v); err != nil { + return &ValidationError{Name: "social_id", err: fmt.Errorf("ent: validator failed for field \"social_id\": %w", err)} + } + } + if _, ok := ac.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New("ent: missing required field \"name\"")} + } + if v, ok := ac.mutation.Name(); ok { + if err := account.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf("ent: validator failed for field \"name\": %w", err)} + } + } + if _, ok := ac.mutation.CreateAt(); !ok { + return &ValidationError{Name: "create_at", err: errors.New("ent: missing required field \"create_at\"")} + } + if _, ok := ac.mutation.UpdateAt(); !ok { + return &ValidationError{Name: "update_at", err: errors.New("ent: missing required field \"update_at\"")} + } + return nil +} + +func (ac *AccountCreate) sqlSave(ctx context.Context) (*Account, error) { + _node, _spec := ac.createSpec() + if err := sqlgraph.CreateNode(ctx, ac.driver, _spec); err != nil { + if cerr, ok := isSQLConstraintError(err); ok { + err = cerr + } + return nil, err + } + return _node, nil +} + +func (ac *AccountCreate) createSpec() (*Account, *sqlgraph.CreateSpec) { + var ( + _node = &Account{config: ac.config} + _spec = &sqlgraph.CreateSpec{ + Table: account.Table, + ID: &sqlgraph.FieldSpec{ + Type: field.TypeUUID, + Column: account.FieldID, + }, + } + ) + if id, ok := ac.mutation.ID(); ok { + _node.ID = id + _spec.ID.Value = id + } + if value, ok := ac.mutation.SocialType(); ok { + _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ + Type: field.TypeUint8, + Value: value, + Column: account.FieldSocialType, + }) + _node.SocialType = value + } + if value, ok := ac.mutation.SocialID(); ok { + _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: account.FieldSocialID, + }) + _node.SocialID = value + } + if value, ok := ac.mutation.Name(); ok { + _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: account.FieldName, + }) + _node.Name = value + } + if value, ok := ac.mutation.CreateAt(); ok { + _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Value: value, + Column: account.FieldCreateAt, + }) + _node.CreateAt = value + } + if value, ok := ac.mutation.UpdateAt(); ok { + _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Value: value, + Column: account.FieldUpdateAt, + }) + _node.UpdateAt = value + } + if value, ok := ac.mutation.DeleteAt(); ok { + _spec.Fields = append(_spec.Fields, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Value: value, + Column: account.FieldDeleteAt, + }) + _node.DeleteAt = &value + } + return _node, _spec +} + +// AccountCreateBulk is the builder for creating many Account entities in bulk. +type AccountCreateBulk struct { + config + builders []*AccountCreate +} + +// Save creates the Account entities in the database. +func (acb *AccountCreateBulk) Save(ctx context.Context) ([]*Account, error) { + specs := make([]*sqlgraph.CreateSpec, len(acb.builders)) + nodes := make([]*Account, len(acb.builders)) + mutators := make([]Mutator, len(acb.builders)) + for i := range acb.builders { + func(i int, root context.Context) { + builder := acb.builders[i] + builder.defaults() + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*AccountMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + nodes[i], specs[i] = builder.createSpec() + var err error + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, acb.builders[i+1].mutation) + } else { + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, acb.driver, &sqlgraph.BatchCreateSpec{Nodes: specs}); err != nil { + if cerr, ok := isSQLConstraintError(err); ok { + err = cerr + } + } + } + mutation.done = true + if err != nil { + return nil, err + } + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, acb.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (acb *AccountCreateBulk) SaveX(ctx context.Context) []*Account { + v, err := acb.Save(ctx) + if err != nil { + panic(err) + } + return v +} diff --git a/ent/account_delete.go b/ent/account_delete.go new file mode 100644 index 0000000..6002011 --- /dev/null +++ b/ent/account_delete.go @@ -0,0 +1,108 @@ +// Code generated by entc, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "github/four-servings/meonzi/ent/account" + "github/four-servings/meonzi/ent/predicate" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" +) + +// AccountDelete is the builder for deleting a Account entity. +type AccountDelete struct { + config + hooks []Hook + mutation *AccountMutation +} + +// Where adds a new predicate to the AccountDelete builder. +func (ad *AccountDelete) Where(ps ...predicate.Account) *AccountDelete { + ad.mutation.predicates = append(ad.mutation.predicates, ps...) + return ad +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (ad *AccountDelete) Exec(ctx context.Context) (int, error) { + var ( + err error + affected int + ) + if len(ad.hooks) == 0 { + affected, err = ad.sqlExec(ctx) + } else { + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*AccountMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + ad.mutation = mutation + affected, err = ad.sqlExec(ctx) + mutation.done = true + return affected, err + }) + for i := len(ad.hooks) - 1; i >= 0; i-- { + mut = ad.hooks[i](mut) + } + if _, err := mut.Mutate(ctx, ad.mutation); err != nil { + return 0, err + } + } + return affected, err +} + +// ExecX is like Exec, but panics if an error occurs. +func (ad *AccountDelete) ExecX(ctx context.Context) int { + n, err := ad.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (ad *AccountDelete) sqlExec(ctx context.Context) (int, error) { + _spec := &sqlgraph.DeleteSpec{ + Node: &sqlgraph.NodeSpec{ + Table: account.Table, + ID: &sqlgraph.FieldSpec{ + Type: field.TypeUUID, + Column: account.FieldID, + }, + }, + } + if ps := ad.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return sqlgraph.DeleteNodes(ctx, ad.driver, _spec) +} + +// AccountDeleteOne is the builder for deleting a single Account entity. +type AccountDeleteOne struct { + ad *AccountDelete +} + +// Exec executes the deletion query. +func (ado *AccountDeleteOne) Exec(ctx context.Context) error { + n, err := ado.ad.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{account.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (ado *AccountDeleteOne) ExecX(ctx context.Context) { + ado.ad.ExecX(ctx) +} diff --git a/ent/account_query.go b/ent/account_query.go new file mode 100644 index 0000000..3852794 --- /dev/null +++ b/ent/account_query.go @@ -0,0 +1,896 @@ +// Code generated by entc, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "github/four-servings/meonzi/ent/account" + "github/four-servings/meonzi/ent/predicate" + "math" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" + "github.com/google/uuid" +) + +// AccountQuery is the builder for querying Account entities. +type AccountQuery struct { + config + limit *int + offset *int + order []OrderFunc + fields []string + predicates []predicate.Account + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the AccountQuery builder. +func (aq *AccountQuery) Where(ps ...predicate.Account) *AccountQuery { + aq.predicates = append(aq.predicates, ps...) + return aq +} + +// Limit adds a limit step to the query. +func (aq *AccountQuery) Limit(limit int) *AccountQuery { + aq.limit = &limit + return aq +} + +// Offset adds an offset step to the query. +func (aq *AccountQuery) Offset(offset int) *AccountQuery { + aq.offset = &offset + return aq +} + +// Order adds an order step to the query. +func (aq *AccountQuery) Order(o ...OrderFunc) *AccountQuery { + aq.order = append(aq.order, o...) + return aq +} + +// First returns the first Account entity from the query. +// Returns a *NotFoundError when no Account was found. +func (aq *AccountQuery) First(ctx context.Context) (*Account, error) { + nodes, err := aq.Limit(1).All(ctx) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{account.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (aq *AccountQuery) FirstX(ctx context.Context) *Account { + node, err := aq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first Account ID from the query. +// Returns a *NotFoundError when no Account ID was found. +func (aq *AccountQuery) FirstID(ctx context.Context) (id uuid.UUID, err error) { + var ids []uuid.UUID + if ids, err = aq.Limit(1).IDs(ctx); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{account.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (aq *AccountQuery) FirstIDX(ctx context.Context) uuid.UUID { + id, err := aq.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single Account entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when exactly one Account entity is not found. +// Returns a *NotFoundError when no Account entities are found. +func (aq *AccountQuery) Only(ctx context.Context) (*Account, error) { + nodes, err := aq.Limit(2).All(ctx) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{account.Label} + default: + return nil, &NotSingularError{account.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (aq *AccountQuery) OnlyX(ctx context.Context) *Account { + node, err := aq.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only Account ID in the query. +// Returns a *NotSingularError when exactly one Account ID is not found. +// Returns a *NotFoundError when no entities are found. +func (aq *AccountQuery) OnlyID(ctx context.Context) (id uuid.UUID, err error) { + var ids []uuid.UUID + if ids, err = aq.Limit(2).IDs(ctx); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{account.Label} + default: + err = &NotSingularError{account.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (aq *AccountQuery) OnlyIDX(ctx context.Context) uuid.UUID { + id, err := aq.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of Accounts. +func (aq *AccountQuery) All(ctx context.Context) ([]*Account, error) { + if err := aq.prepareQuery(ctx); err != nil { + return nil, err + } + return aq.sqlAll(ctx) +} + +// AllX is like All, but panics if an error occurs. +func (aq *AccountQuery) AllX(ctx context.Context) []*Account { + nodes, err := aq.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of Account IDs. +func (aq *AccountQuery) IDs(ctx context.Context) ([]uuid.UUID, error) { + var ids []uuid.UUID + if err := aq.Select(account.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (aq *AccountQuery) IDsX(ctx context.Context) []uuid.UUID { + ids, err := aq.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (aq *AccountQuery) Count(ctx context.Context) (int, error) { + if err := aq.prepareQuery(ctx); err != nil { + return 0, err + } + return aq.sqlCount(ctx) +} + +// CountX is like Count, but panics if an error occurs. +func (aq *AccountQuery) CountX(ctx context.Context) int { + count, err := aq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (aq *AccountQuery) Exist(ctx context.Context) (bool, error) { + if err := aq.prepareQuery(ctx); err != nil { + return false, err + } + return aq.sqlExist(ctx) +} + +// ExistX is like Exist, but panics if an error occurs. +func (aq *AccountQuery) ExistX(ctx context.Context) bool { + exist, err := aq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the AccountQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (aq *AccountQuery) Clone() *AccountQuery { + if aq == nil { + return nil + } + return &AccountQuery{ + config: aq.config, + limit: aq.limit, + offset: aq.offset, + order: append([]OrderFunc{}, aq.order...), + predicates: append([]predicate.Account{}, aq.predicates...), + // clone intermediate query. + sql: aq.sql.Clone(), + path: aq.path, + } +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// SocialType schema.SocialType `json:"social_type,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.Account.Query(). +// GroupBy(account.FieldSocialType). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +// +func (aq *AccountQuery) GroupBy(field string, fields ...string) *AccountGroupBy { + group := &AccountGroupBy{config: aq.config} + group.fields = append([]string{field}, fields...) + group.path = func(ctx context.Context) (prev *sql.Selector, err error) { + if err := aq.prepareQuery(ctx); err != nil { + return nil, err + } + return aq.sqlQuery(ctx), nil + } + return group +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// SocialType schema.SocialType `json:"social_type,omitempty"` +// } +// +// client.Account.Query(). +// Select(account.FieldSocialType). +// Scan(ctx, &v) +// +func (aq *AccountQuery) Select(field string, fields ...string) *AccountSelect { + aq.fields = append([]string{field}, fields...) + return &AccountSelect{AccountQuery: aq} +} + +func (aq *AccountQuery) prepareQuery(ctx context.Context) error { + for _, f := range aq.fields { + if !account.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if aq.path != nil { + prev, err := aq.path(ctx) + if err != nil { + return err + } + aq.sql = prev + } + return nil +} + +func (aq *AccountQuery) sqlAll(ctx context.Context) ([]*Account, error) { + var ( + nodes = []*Account{} + _spec = aq.querySpec() + ) + _spec.ScanValues = func(columns []string) ([]interface{}, error) { + node := &Account{config: aq.config} + nodes = append(nodes, node) + return node.scanValues(columns) + } + _spec.Assign = func(columns []string, values []interface{}) error { + if len(nodes) == 0 { + return fmt.Errorf("ent: Assign called without calling ScanValues") + } + node := nodes[len(nodes)-1] + return node.assignValues(columns, values) + } + if err := sqlgraph.QueryNodes(ctx, aq.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + return nodes, nil +} + +func (aq *AccountQuery) sqlCount(ctx context.Context) (int, error) { + _spec := aq.querySpec() + return sqlgraph.CountNodes(ctx, aq.driver, _spec) +} + +func (aq *AccountQuery) sqlExist(ctx context.Context) (bool, error) { + n, err := aq.sqlCount(ctx) + if err != nil { + return false, fmt.Errorf("ent: check existence: %v", err) + } + return n > 0, nil +} + +func (aq *AccountQuery) querySpec() *sqlgraph.QuerySpec { + _spec := &sqlgraph.QuerySpec{ + Node: &sqlgraph.NodeSpec{ + Table: account.Table, + Columns: account.Columns, + ID: &sqlgraph.FieldSpec{ + Type: field.TypeUUID, + Column: account.FieldID, + }, + }, + From: aq.sql, + Unique: true, + } + if fields := aq.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, account.FieldID) + for i := range fields { + if fields[i] != account.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + } + if ps := aq.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := aq.limit; limit != nil { + _spec.Limit = *limit + } + if offset := aq.offset; offset != nil { + _spec.Offset = *offset + } + if ps := aq.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector, account.ValidColumn) + } + } + } + return _spec +} + +func (aq *AccountQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(aq.driver.Dialect()) + t1 := builder.Table(account.Table) + selector := builder.Select(t1.Columns(account.Columns...)...).From(t1) + if aq.sql != nil { + selector = aq.sql + selector.Select(selector.Columns(account.Columns...)...) + } + for _, p := range aq.predicates { + p(selector) + } + for _, p := range aq.order { + p(selector, account.ValidColumn) + } + if offset := aq.offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := aq.limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// AccountGroupBy is the group-by builder for Account entities. +type AccountGroupBy struct { + config + fields []string + fns []AggregateFunc + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (agb *AccountGroupBy) Aggregate(fns ...AggregateFunc) *AccountGroupBy { + agb.fns = append(agb.fns, fns...) + return agb +} + +// Scan applies the group-by query and scans the result into the given value. +func (agb *AccountGroupBy) Scan(ctx context.Context, v interface{}) error { + query, err := agb.path(ctx) + if err != nil { + return err + } + agb.sql = query + return agb.sqlScan(ctx, v) +} + +// ScanX is like Scan, but panics if an error occurs. +func (agb *AccountGroupBy) ScanX(ctx context.Context, v interface{}) { + if err := agb.Scan(ctx, v); err != nil { + panic(err) + } +} + +// Strings returns list of strings from group-by. +// It is only allowed when executing a group-by query with one field. +func (agb *AccountGroupBy) Strings(ctx context.Context) ([]string, error) { + if len(agb.fields) > 1 { + return nil, errors.New("ent: AccountGroupBy.Strings is not achievable when grouping more than 1 field") + } + var v []string + if err := agb.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// StringsX is like Strings, but panics if an error occurs. +func (agb *AccountGroupBy) StringsX(ctx context.Context) []string { + v, err := agb.Strings(ctx) + if err != nil { + panic(err) + } + return v +} + +// String returns a single string from a group-by query. +// It is only allowed when executing a group-by query with one field. +func (agb *AccountGroupBy) String(ctx context.Context) (_ string, err error) { + var v []string + if v, err = agb.Strings(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{account.Label} + default: + err = fmt.Errorf("ent: AccountGroupBy.Strings returned %d results when one was expected", len(v)) + } + return +} + +// StringX is like String, but panics if an error occurs. +func (agb *AccountGroupBy) StringX(ctx context.Context) string { + v, err := agb.String(ctx) + if err != nil { + panic(err) + } + return v +} + +// Ints returns list of ints from group-by. +// It is only allowed when executing a group-by query with one field. +func (agb *AccountGroupBy) Ints(ctx context.Context) ([]int, error) { + if len(agb.fields) > 1 { + return nil, errors.New("ent: AccountGroupBy.Ints is not achievable when grouping more than 1 field") + } + var v []int + if err := agb.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// IntsX is like Ints, but panics if an error occurs. +func (agb *AccountGroupBy) IntsX(ctx context.Context) []int { + v, err := agb.Ints(ctx) + if err != nil { + panic(err) + } + return v +} + +// Int returns a single int from a group-by query. +// It is only allowed when executing a group-by query with one field. +func (agb *AccountGroupBy) Int(ctx context.Context) (_ int, err error) { + var v []int + if v, err = agb.Ints(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{account.Label} + default: + err = fmt.Errorf("ent: AccountGroupBy.Ints returned %d results when one was expected", len(v)) + } + return +} + +// IntX is like Int, but panics if an error occurs. +func (agb *AccountGroupBy) IntX(ctx context.Context) int { + v, err := agb.Int(ctx) + if err != nil { + panic(err) + } + return v +} + +// Float64s returns list of float64s from group-by. +// It is only allowed when executing a group-by query with one field. +func (agb *AccountGroupBy) Float64s(ctx context.Context) ([]float64, error) { + if len(agb.fields) > 1 { + return nil, errors.New("ent: AccountGroupBy.Float64s is not achievable when grouping more than 1 field") + } + var v []float64 + if err := agb.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// Float64sX is like Float64s, but panics if an error occurs. +func (agb *AccountGroupBy) Float64sX(ctx context.Context) []float64 { + v, err := agb.Float64s(ctx) + if err != nil { + panic(err) + } + return v +} + +// Float64 returns a single float64 from a group-by query. +// It is only allowed when executing a group-by query with one field. +func (agb *AccountGroupBy) Float64(ctx context.Context) (_ float64, err error) { + var v []float64 + if v, err = agb.Float64s(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{account.Label} + default: + err = fmt.Errorf("ent: AccountGroupBy.Float64s returned %d results when one was expected", len(v)) + } + return +} + +// Float64X is like Float64, but panics if an error occurs. +func (agb *AccountGroupBy) Float64X(ctx context.Context) float64 { + v, err := agb.Float64(ctx) + if err != nil { + panic(err) + } + return v +} + +// Bools returns list of bools from group-by. +// It is only allowed when executing a group-by query with one field. +func (agb *AccountGroupBy) Bools(ctx context.Context) ([]bool, error) { + if len(agb.fields) > 1 { + return nil, errors.New("ent: AccountGroupBy.Bools is not achievable when grouping more than 1 field") + } + var v []bool + if err := agb.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// BoolsX is like Bools, but panics if an error occurs. +func (agb *AccountGroupBy) BoolsX(ctx context.Context) []bool { + v, err := agb.Bools(ctx) + if err != nil { + panic(err) + } + return v +} + +// Bool returns a single bool from a group-by query. +// It is only allowed when executing a group-by query with one field. +func (agb *AccountGroupBy) Bool(ctx context.Context) (_ bool, err error) { + var v []bool + if v, err = agb.Bools(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{account.Label} + default: + err = fmt.Errorf("ent: AccountGroupBy.Bools returned %d results when one was expected", len(v)) + } + return +} + +// BoolX is like Bool, but panics if an error occurs. +func (agb *AccountGroupBy) BoolX(ctx context.Context) bool { + v, err := agb.Bool(ctx) + if err != nil { + panic(err) + } + return v +} + +func (agb *AccountGroupBy) sqlScan(ctx context.Context, v interface{}) error { + for _, f := range agb.fields { + if !account.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("invalid field %q for group-by", f)} + } + } + selector := agb.sqlQuery() + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := agb.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +func (agb *AccountGroupBy) sqlQuery() *sql.Selector { + selector := agb.sql + columns := make([]string, 0, len(agb.fields)+len(agb.fns)) + columns = append(columns, agb.fields...) + for _, fn := range agb.fns { + columns = append(columns, fn(selector, account.ValidColumn)) + } + return selector.Select(columns...).GroupBy(agb.fields...) +} + +// AccountSelect is the builder for selecting fields of Account entities. +type AccountSelect struct { + *AccountQuery + // intermediate query (i.e. traversal path). + sql *sql.Selector +} + +// Scan applies the selector query and scans the result into the given value. +func (as *AccountSelect) Scan(ctx context.Context, v interface{}) error { + if err := as.prepareQuery(ctx); err != nil { + return err + } + as.sql = as.AccountQuery.sqlQuery(ctx) + return as.sqlScan(ctx, v) +} + +// ScanX is like Scan, but panics if an error occurs. +func (as *AccountSelect) ScanX(ctx context.Context, v interface{}) { + if err := as.Scan(ctx, v); err != nil { + panic(err) + } +} + +// Strings returns list of strings from a selector. It is only allowed when selecting one field. +func (as *AccountSelect) Strings(ctx context.Context) ([]string, error) { + if len(as.fields) > 1 { + return nil, errors.New("ent: AccountSelect.Strings is not achievable when selecting more than 1 field") + } + var v []string + if err := as.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// StringsX is like Strings, but panics if an error occurs. +func (as *AccountSelect) StringsX(ctx context.Context) []string { + v, err := as.Strings(ctx) + if err != nil { + panic(err) + } + return v +} + +// String returns a single string from a selector. It is only allowed when selecting one field. +func (as *AccountSelect) String(ctx context.Context) (_ string, err error) { + var v []string + if v, err = as.Strings(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{account.Label} + default: + err = fmt.Errorf("ent: AccountSelect.Strings returned %d results when one was expected", len(v)) + } + return +} + +// StringX is like String, but panics if an error occurs. +func (as *AccountSelect) StringX(ctx context.Context) string { + v, err := as.String(ctx) + if err != nil { + panic(err) + } + return v +} + +// Ints returns list of ints from a selector. It is only allowed when selecting one field. +func (as *AccountSelect) Ints(ctx context.Context) ([]int, error) { + if len(as.fields) > 1 { + return nil, errors.New("ent: AccountSelect.Ints is not achievable when selecting more than 1 field") + } + var v []int + if err := as.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// IntsX is like Ints, but panics if an error occurs. +func (as *AccountSelect) IntsX(ctx context.Context) []int { + v, err := as.Ints(ctx) + if err != nil { + panic(err) + } + return v +} + +// Int returns a single int from a selector. It is only allowed when selecting one field. +func (as *AccountSelect) Int(ctx context.Context) (_ int, err error) { + var v []int + if v, err = as.Ints(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{account.Label} + default: + err = fmt.Errorf("ent: AccountSelect.Ints returned %d results when one was expected", len(v)) + } + return +} + +// IntX is like Int, but panics if an error occurs. +func (as *AccountSelect) IntX(ctx context.Context) int { + v, err := as.Int(ctx) + if err != nil { + panic(err) + } + return v +} + +// Float64s returns list of float64s from a selector. It is only allowed when selecting one field. +func (as *AccountSelect) Float64s(ctx context.Context) ([]float64, error) { + if len(as.fields) > 1 { + return nil, errors.New("ent: AccountSelect.Float64s is not achievable when selecting more than 1 field") + } + var v []float64 + if err := as.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// Float64sX is like Float64s, but panics if an error occurs. +func (as *AccountSelect) Float64sX(ctx context.Context) []float64 { + v, err := as.Float64s(ctx) + if err != nil { + panic(err) + } + return v +} + +// Float64 returns a single float64 from a selector. It is only allowed when selecting one field. +func (as *AccountSelect) Float64(ctx context.Context) (_ float64, err error) { + var v []float64 + if v, err = as.Float64s(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{account.Label} + default: + err = fmt.Errorf("ent: AccountSelect.Float64s returned %d results when one was expected", len(v)) + } + return +} + +// Float64X is like Float64, but panics if an error occurs. +func (as *AccountSelect) Float64X(ctx context.Context) float64 { + v, err := as.Float64(ctx) + if err != nil { + panic(err) + } + return v +} + +// Bools returns list of bools from a selector. It is only allowed when selecting one field. +func (as *AccountSelect) Bools(ctx context.Context) ([]bool, error) { + if len(as.fields) > 1 { + return nil, errors.New("ent: AccountSelect.Bools is not achievable when selecting more than 1 field") + } + var v []bool + if err := as.Scan(ctx, &v); err != nil { + return nil, err + } + return v, nil +} + +// BoolsX is like Bools, but panics if an error occurs. +func (as *AccountSelect) BoolsX(ctx context.Context) []bool { + v, err := as.Bools(ctx) + if err != nil { + panic(err) + } + return v +} + +// Bool returns a single bool from a selector. It is only allowed when selecting one field. +func (as *AccountSelect) Bool(ctx context.Context) (_ bool, err error) { + var v []bool + if v, err = as.Bools(ctx); err != nil { + return + } + switch len(v) { + case 1: + return v[0], nil + case 0: + err = &NotFoundError{account.Label} + default: + err = fmt.Errorf("ent: AccountSelect.Bools returned %d results when one was expected", len(v)) + } + return +} + +// BoolX is like Bool, but panics if an error occurs. +func (as *AccountSelect) BoolX(ctx context.Context) bool { + v, err := as.Bool(ctx) + if err != nil { + panic(err) + } + return v +} + +func (as *AccountSelect) sqlScan(ctx context.Context, v interface{}) error { + rows := &sql.Rows{} + query, args := as.sqlQuery().Query() + if err := as.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +func (as *AccountSelect) sqlQuery() sql.Querier { + selector := as.sql + selector.Select(selector.Columns(as.fields...)...) + return selector +} diff --git a/ent/account_update.go b/ent/account_update.go new file mode 100644 index 0000000..61b5920 --- /dev/null +++ b/ent/account_update.go @@ -0,0 +1,381 @@ +// Code generated by entc, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "github/four-servings/meonzi/ent/account" + "github/four-servings/meonzi/ent/predicate" + "time" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" +) + +// AccountUpdate is the builder for updating Account entities. +type AccountUpdate struct { + config + hooks []Hook + mutation *AccountMutation +} + +// Where adds a new predicate for the AccountUpdate builder. +func (au *AccountUpdate) Where(ps ...predicate.Account) *AccountUpdate { + au.mutation.predicates = append(au.mutation.predicates, ps...) + return au +} + +// SetName sets the "name" field. +func (au *AccountUpdate) SetName(s string) *AccountUpdate { + au.mutation.SetName(s) + return au +} + +// SetUpdateAt sets the "update_at" field. +func (au *AccountUpdate) SetUpdateAt(t time.Time) *AccountUpdate { + au.mutation.SetUpdateAt(t) + return au +} + +// SetDeleteAt sets the "delete_at" field. +func (au *AccountUpdate) SetDeleteAt(t time.Time) *AccountUpdate { + au.mutation.SetDeleteAt(t) + return au +} + +// SetNillableDeleteAt sets the "delete_at" field if the given value is not nil. +func (au *AccountUpdate) SetNillableDeleteAt(t *time.Time) *AccountUpdate { + if t != nil { + au.SetDeleteAt(*t) + } + return au +} + +// ClearDeleteAt clears the value of the "delete_at" field. +func (au *AccountUpdate) ClearDeleteAt() *AccountUpdate { + au.mutation.ClearDeleteAt() + return au +} + +// Mutation returns the AccountMutation object of the builder. +func (au *AccountUpdate) Mutation() *AccountMutation { + return au.mutation +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (au *AccountUpdate) Save(ctx context.Context) (int, error) { + var ( + err error + affected int + ) + au.defaults() + if len(au.hooks) == 0 { + if err = au.check(); err != nil { + return 0, err + } + affected, err = au.sqlSave(ctx) + } else { + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*AccountMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err = au.check(); err != nil { + return 0, err + } + au.mutation = mutation + affected, err = au.sqlSave(ctx) + mutation.done = true + return affected, err + }) + for i := len(au.hooks) - 1; i >= 0; i-- { + mut = au.hooks[i](mut) + } + if _, err := mut.Mutate(ctx, au.mutation); err != nil { + return 0, err + } + } + return affected, err +} + +// SaveX is like Save, but panics if an error occurs. +func (au *AccountUpdate) SaveX(ctx context.Context) int { + affected, err := au.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (au *AccountUpdate) Exec(ctx context.Context) error { + _, err := au.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (au *AccountUpdate) ExecX(ctx context.Context) { + if err := au.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (au *AccountUpdate) defaults() { + if _, ok := au.mutation.UpdateAt(); !ok { + v := account.UpdateDefaultUpdateAt() + au.mutation.SetUpdateAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (au *AccountUpdate) check() error { + if v, ok := au.mutation.Name(); ok { + if err := account.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf("ent: validator failed for field \"name\": %w", err)} + } + } + return nil +} + +func (au *AccountUpdate) sqlSave(ctx context.Context) (n int, err error) { + _spec := &sqlgraph.UpdateSpec{ + Node: &sqlgraph.NodeSpec{ + Table: account.Table, + Columns: account.Columns, + ID: &sqlgraph.FieldSpec{ + Type: field.TypeUUID, + Column: account.FieldID, + }, + }, + } + if ps := au.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := au.mutation.Name(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: account.FieldName, + }) + } + if value, ok := au.mutation.UpdateAt(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Value: value, + Column: account.FieldUpdateAt, + }) + } + if value, ok := au.mutation.DeleteAt(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Value: value, + Column: account.FieldDeleteAt, + }) + } + if au.mutation.DeleteAtCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Column: account.FieldDeleteAt, + }) + } + if n, err = sqlgraph.UpdateNodes(ctx, au.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{account.Label} + } else if cerr, ok := isSQLConstraintError(err); ok { + err = cerr + } + return 0, err + } + return n, nil +} + +// AccountUpdateOne is the builder for updating a single Account entity. +type AccountUpdateOne struct { + config + hooks []Hook + mutation *AccountMutation +} + +// SetName sets the "name" field. +func (auo *AccountUpdateOne) SetName(s string) *AccountUpdateOne { + auo.mutation.SetName(s) + return auo +} + +// SetUpdateAt sets the "update_at" field. +func (auo *AccountUpdateOne) SetUpdateAt(t time.Time) *AccountUpdateOne { + auo.mutation.SetUpdateAt(t) + return auo +} + +// SetDeleteAt sets the "delete_at" field. +func (auo *AccountUpdateOne) SetDeleteAt(t time.Time) *AccountUpdateOne { + auo.mutation.SetDeleteAt(t) + return auo +} + +// SetNillableDeleteAt sets the "delete_at" field if the given value is not nil. +func (auo *AccountUpdateOne) SetNillableDeleteAt(t *time.Time) *AccountUpdateOne { + if t != nil { + auo.SetDeleteAt(*t) + } + return auo +} + +// ClearDeleteAt clears the value of the "delete_at" field. +func (auo *AccountUpdateOne) ClearDeleteAt() *AccountUpdateOne { + auo.mutation.ClearDeleteAt() + return auo +} + +// Mutation returns the AccountMutation object of the builder. +func (auo *AccountUpdateOne) Mutation() *AccountMutation { + return auo.mutation +} + +// Save executes the query and returns the updated Account entity. +func (auo *AccountUpdateOne) Save(ctx context.Context) (*Account, error) { + var ( + err error + node *Account + ) + auo.defaults() + if len(auo.hooks) == 0 { + if err = auo.check(); err != nil { + return nil, err + } + node, err = auo.sqlSave(ctx) + } else { + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*AccountMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err = auo.check(); err != nil { + return nil, err + } + auo.mutation = mutation + node, err = auo.sqlSave(ctx) + mutation.done = true + return node, err + }) + for i := len(auo.hooks) - 1; i >= 0; i-- { + mut = auo.hooks[i](mut) + } + if _, err := mut.Mutate(ctx, auo.mutation); err != nil { + return nil, err + } + } + return node, err +} + +// SaveX is like Save, but panics if an error occurs. +func (auo *AccountUpdateOne) SaveX(ctx context.Context) *Account { + node, err := auo.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (auo *AccountUpdateOne) Exec(ctx context.Context) error { + _, err := auo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (auo *AccountUpdateOne) ExecX(ctx context.Context) { + if err := auo.Exec(ctx); err != nil { + panic(err) + } +} + +// defaults sets the default values of the builder before save. +func (auo *AccountUpdateOne) defaults() { + if _, ok := auo.mutation.UpdateAt(); !ok { + v := account.UpdateDefaultUpdateAt() + auo.mutation.SetUpdateAt(v) + } +} + +// check runs all checks and user-defined validators on the builder. +func (auo *AccountUpdateOne) check() error { + if v, ok := auo.mutation.Name(); ok { + if err := account.NameValidator(v); err != nil { + return &ValidationError{Name: "name", err: fmt.Errorf("ent: validator failed for field \"name\": %w", err)} + } + } + return nil +} + +func (auo *AccountUpdateOne) sqlSave(ctx context.Context) (_node *Account, err error) { + _spec := &sqlgraph.UpdateSpec{ + Node: &sqlgraph.NodeSpec{ + Table: account.Table, + Columns: account.Columns, + ID: &sqlgraph.FieldSpec{ + Type: field.TypeUUID, + Column: account.FieldID, + }, + }, + } + id, ok := auo.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "ID", err: fmt.Errorf("missing Account.ID for update")} + } + _spec.Node.ID.Value = id + if ps := auo.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := auo.mutation.Name(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeString, + Value: value, + Column: account.FieldName, + }) + } + if value, ok := auo.mutation.UpdateAt(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Value: value, + Column: account.FieldUpdateAt, + }) + } + if value, ok := auo.mutation.DeleteAt(); ok { + _spec.Fields.Set = append(_spec.Fields.Set, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Value: value, + Column: account.FieldDeleteAt, + }) + } + if auo.mutation.DeleteAtCleared() { + _spec.Fields.Clear = append(_spec.Fields.Clear, &sqlgraph.FieldSpec{ + Type: field.TypeTime, + Column: account.FieldDeleteAt, + }) + } + _node = &Account{config: auo.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, auo.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{account.Label} + } else if cerr, ok := isSQLConstraintError(err); ok { + err = cerr + } + return nil, err + } + return _node, nil +} diff --git a/ent/client.go b/ent/client.go new file mode 100644 index 0000000..ab76f91 --- /dev/null +++ b/ent/client.go @@ -0,0 +1,211 @@ +// Code generated by entc, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "log" + + "github/four-servings/meonzi/ent/migrate" + + "github/four-servings/meonzi/ent/account" + + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/sql" + "github.com/google/uuid" +) + +// Client is the client that holds all ent builders. +type Client struct { + config + // Schema is the client for creating, migrating and dropping schema. + Schema *migrate.Schema + // Account is the client for interacting with the Account builders. + Account *AccountClient +} + +// NewClient creates a new client configured with the given options. +func NewClient(opts ...Option) *Client { + cfg := config{log: log.Println, hooks: &hooks{}} + cfg.options(opts...) + client := &Client{config: cfg} + client.init() + return client +} + +func (c *Client) init() { + c.Schema = migrate.NewSchema(c.driver) + c.Account = NewAccountClient(c.config) +} + +// Open opens a database/sql.DB specified by the driver name and +// the data source name, and returns a new client attached to it. +// Optional parameters can be added for configuring the client. +func Open(driverName, dataSourceName string, options ...Option) (*Client, error) { + switch driverName { + case dialect.MySQL, dialect.Postgres, dialect.SQLite: + drv, err := sql.Open(driverName, dataSourceName) + if err != nil { + return nil, err + } + return NewClient(append(options, Driver(drv))...), nil + default: + return nil, fmt.Errorf("unsupported driver: %q", driverName) + } +} + +// Tx returns a new transactional client. The provided context +// is used until the transaction is committed or rolled back. +func (c *Client) Tx(ctx context.Context) (*Tx, error) { + if _, ok := c.driver.(*txDriver); ok { + return nil, fmt.Errorf("ent: cannot start a transaction within a transaction") + } + tx, err := newTx(ctx, c.driver) + if err != nil { + return nil, fmt.Errorf("ent: starting a transaction: %v", err) + } + cfg := c.config + cfg.driver = tx + return &Tx{ + ctx: ctx, + config: cfg, + Account: NewAccountClient(cfg), + }, nil +} + +// BeginTx returns a transactional client with specified options. +func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) { + if _, ok := c.driver.(*txDriver); ok { + return nil, fmt.Errorf("ent: cannot start a transaction within a transaction") + } + tx, err := c.driver.(interface { + BeginTx(context.Context, *sql.TxOptions) (dialect.Tx, error) + }).BeginTx(ctx, opts) + if err != nil { + return nil, fmt.Errorf("ent: starting a transaction: %v", err) + } + cfg := c.config + cfg.driver = &txDriver{tx: tx, drv: c.driver} + return &Tx{ + config: cfg, + Account: NewAccountClient(cfg), + }, nil +} + +// Debug returns a new debug-client. It's used to get verbose logging on specific operations. +// +// client.Debug(). +// Account. +// Query(). +// Count(ctx) +// +func (c *Client) Debug() *Client { + if c.debug { + return c + } + cfg := c.config + cfg.driver = dialect.Debug(c.driver, c.log) + client := &Client{config: cfg} + client.init() + return client +} + +// Close closes the database connection and prevents new queries from starting. +func (c *Client) Close() error { + return c.driver.Close() +} + +// Use adds the mutation hooks to all the entity clients. +// In order to add hooks to a specific client, call: `client.Node.Use(...)`. +func (c *Client) Use(hooks ...Hook) { + c.Account.Use(hooks...) +} + +// AccountClient is a client for the Account schema. +type AccountClient struct { + config +} + +// NewAccountClient returns a client for the Account from the given config. +func NewAccountClient(c config) *AccountClient { + return &AccountClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `account.Hooks(f(g(h())))`. +func (c *AccountClient) Use(hooks ...Hook) { + c.hooks.Account = append(c.hooks.Account, hooks...) +} + +// Create returns a create builder for Account. +func (c *AccountClient) Create() *AccountCreate { + mutation := newAccountMutation(c.config, OpCreate) + return &AccountCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of Account entities. +func (c *AccountClient) CreateBulk(builders ...*AccountCreate) *AccountCreateBulk { + return &AccountCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for Account. +func (c *AccountClient) Update() *AccountUpdate { + mutation := newAccountMutation(c.config, OpUpdate) + return &AccountUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *AccountClient) UpdateOne(a *Account) *AccountUpdateOne { + mutation := newAccountMutation(c.config, OpUpdateOne, withAccount(a)) + return &AccountUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *AccountClient) UpdateOneID(id uuid.UUID) *AccountUpdateOne { + mutation := newAccountMutation(c.config, OpUpdateOne, withAccountID(id)) + return &AccountUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for Account. +func (c *AccountClient) Delete() *AccountDelete { + mutation := newAccountMutation(c.config, OpDelete) + return &AccountDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a delete builder for the given entity. +func (c *AccountClient) DeleteOne(a *Account) *AccountDeleteOne { + return c.DeleteOneID(a.ID) +} + +// DeleteOneID returns a delete builder for the given id. +func (c *AccountClient) DeleteOneID(id uuid.UUID) *AccountDeleteOne { + builder := c.Delete().Where(account.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &AccountDeleteOne{builder} +} + +// Query returns a query builder for Account. +func (c *AccountClient) Query() *AccountQuery { + return &AccountQuery{config: c.config} +} + +// Get returns a Account entity by its id. +func (c *AccountClient) Get(ctx context.Context, id uuid.UUID) (*Account, error) { + return c.Query().Where(account.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *AccountClient) GetX(ctx context.Context, id uuid.UUID) *Account { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// Hooks returns the client hooks. +func (c *AccountClient) Hooks() []Hook { + return c.hooks.Account +} diff --git a/ent/config.go b/ent/config.go new file mode 100644 index 0000000..a9dbd43 --- /dev/null +++ b/ent/config.go @@ -0,0 +1,59 @@ +// Code generated by entc, DO NOT EDIT. + +package ent + +import ( + "entgo.io/ent" + "entgo.io/ent/dialect" +) + +// Option function to configure the client. +type Option func(*config) + +// Config is the configuration for the client and its builder. +type config struct { + // driver used for executing database requests. + driver dialect.Driver + // debug enable a debug logging. + debug bool + // log used for logging on debug mode. + log func(...interface{}) + // hooks to execute on mutations. + hooks *hooks +} + +// hooks per client, for fast access. +type hooks struct { + Account []ent.Hook +} + +// Options applies the options on the config object. +func (c *config) options(opts ...Option) { + for _, opt := range opts { + opt(c) + } + if c.debug { + c.driver = dialect.Debug(c.driver, c.log) + } +} + +// Debug enables debug logging on the ent.Driver. +func Debug() Option { + return func(c *config) { + c.debug = true + } +} + +// Log sets the logging function for debug mode. +func Log(fn func(...interface{})) Option { + return func(c *config) { + c.log = fn + } +} + +// Driver configures the client driver. +func Driver(driver dialect.Driver) Option { + return func(c *config) { + c.driver = driver + } +} diff --git a/ent/context.go b/ent/context.go new file mode 100644 index 0000000..0840726 --- /dev/null +++ b/ent/context.go @@ -0,0 +1,33 @@ +// Code generated by entc, DO NOT EDIT. + +package ent + +import ( + "context" +) + +type clientCtxKey struct{} + +// FromContext returns a Client stored inside a context, or nil if there isn't one. +func FromContext(ctx context.Context) *Client { + c, _ := ctx.Value(clientCtxKey{}).(*Client) + return c +} + +// NewContext returns a new context with the given Client attached. +func NewContext(parent context.Context, c *Client) context.Context { + return context.WithValue(parent, clientCtxKey{}, c) +} + +type txCtxKey struct{} + +// TxFromContext returns a Tx stored inside a context, or nil if there isn't one. +func TxFromContext(ctx context.Context) *Tx { + tx, _ := ctx.Value(txCtxKey{}).(*Tx) + return tx +} + +// NewTxContext returns a new context with the given Tx attached. +func NewTxContext(parent context.Context, tx *Tx) context.Context { + return context.WithValue(parent, txCtxKey{}, tx) +} diff --git a/ent/ent.go b/ent/ent.go new file mode 100644 index 0000000..e1f1aa0 --- /dev/null +++ b/ent/ent.go @@ -0,0 +1,270 @@ +// Code generated by entc, DO NOT EDIT. + +package ent + +import ( + "errors" + "fmt" + "strings" + + "entgo.io/ent" + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" +) + +// ent aliases to avoid import conflicts in user's code. +type ( + Op = ent.Op + Hook = ent.Hook + Value = ent.Value + Query = ent.Query + Policy = ent.Policy + Mutator = ent.Mutator + Mutation = ent.Mutation + MutateFunc = ent.MutateFunc +) + +// OrderFunc applies an ordering on the sql selector. +type OrderFunc func(*sql.Selector, func(string) bool) + +// Asc applies the given fields in ASC order. +func Asc(fields ...string) OrderFunc { + return func(s *sql.Selector, check func(string) bool) { + for _, f := range fields { + if check(f) { + s.OrderBy(sql.Asc(f)) + } else { + s.AddError(&ValidationError{Name: f, err: fmt.Errorf("invalid field %q for ordering", f)}) + } + } + } +} + +// Desc applies the given fields in DESC order. +func Desc(fields ...string) OrderFunc { + return func(s *sql.Selector, check func(string) bool) { + for _, f := range fields { + if check(f) { + s.OrderBy(sql.Desc(f)) + } else { + s.AddError(&ValidationError{Name: f, err: fmt.Errorf("invalid field %q for ordering", f)}) + } + } + } +} + +// AggregateFunc applies an aggregation step on the group-by traversal/selector. +type AggregateFunc func(*sql.Selector, func(string) bool) string + +// As is a pseudo aggregation function for renaming another other functions with custom names. For example: +// +// GroupBy(field1, field2). +// Aggregate(ent.As(ent.Sum(field1), "sum_field1"), (ent.As(ent.Sum(field2), "sum_field2")). +// Scan(ctx, &v) +// +func As(fn AggregateFunc, end string) AggregateFunc { + return func(s *sql.Selector, check func(string) bool) string { + return sql.As(fn(s, check), end) + } +} + +// Count applies the "count" aggregation function on each group. +func Count() AggregateFunc { + return func(s *sql.Selector, _ func(string) bool) string { + return sql.Count("*") + } +} + +// Max applies the "max" aggregation function on the given field of each group. +func Max(field string) AggregateFunc { + return func(s *sql.Selector, check func(string) bool) string { + if !check(field) { + s.AddError(&ValidationError{Name: field, err: fmt.Errorf("invalid field %q for grouping", field)}) + return "" + } + return sql.Max(s.C(field)) + } +} + +// Mean applies the "mean" aggregation function on the given field of each group. +func Mean(field string) AggregateFunc { + return func(s *sql.Selector, check func(string) bool) string { + if !check(field) { + s.AddError(&ValidationError{Name: field, err: fmt.Errorf("invalid field %q for grouping", field)}) + return "" + } + return sql.Avg(s.C(field)) + } +} + +// Min applies the "min" aggregation function on the given field of each group. +func Min(field string) AggregateFunc { + return func(s *sql.Selector, check func(string) bool) string { + if !check(field) { + s.AddError(&ValidationError{Name: field, err: fmt.Errorf("invalid field %q for grouping", field)}) + return "" + } + return sql.Min(s.C(field)) + } +} + +// Sum applies the "sum" aggregation function on the given field of each group. +func Sum(field string) AggregateFunc { + return func(s *sql.Selector, check func(string) bool) string { + if !check(field) { + s.AddError(&ValidationError{Name: field, err: fmt.Errorf("invalid field %q for grouping", field)}) + return "" + } + return sql.Sum(s.C(field)) + } +} + +// ValidationError returns when validating a field fails. +type ValidationError struct { + Name string // Field or edge name. + err error +} + +// Error implements the error interface. +func (e *ValidationError) Error() string { + return e.err.Error() +} + +// Unwrap implements the errors.Wrapper interface. +func (e *ValidationError) Unwrap() error { + return e.err +} + +// IsValidationError returns a boolean indicating whether the error is a validaton error. +func IsValidationError(err error) bool { + if err == nil { + return false + } + var e *ValidationError + return errors.As(err, &e) +} + +// NotFoundError returns when trying to fetch a specific entity and it was not found in the database. +type NotFoundError struct { + label string +} + +// Error implements the error interface. +func (e *NotFoundError) Error() string { + return "ent: " + e.label + " not found" +} + +// IsNotFound returns a boolean indicating whether the error is a not found error. +func IsNotFound(err error) bool { + if err == nil { + return false + } + var e *NotFoundError + return errors.As(err, &e) +} + +// MaskNotFound masks not found error. +func MaskNotFound(err error) error { + if IsNotFound(err) { + return nil + } + return err +} + +// NotSingularError returns when trying to fetch a singular entity and more then one was found in the database. +type NotSingularError struct { + label string +} + +// Error implements the error interface. +func (e *NotSingularError) Error() string { + return "ent: " + e.label + " not singular" +} + +// IsNotSingular returns a boolean indicating whether the error is a not singular error. +func IsNotSingular(err error) bool { + if err == nil { + return false + } + var e *NotSingularError + return errors.As(err, &e) +} + +// NotLoadedError returns when trying to get a node that was not loaded by the query. +type NotLoadedError struct { + edge string +} + +// Error implements the error interface. +func (e *NotLoadedError) Error() string { + return "ent: " + e.edge + " edge was not loaded" +} + +// IsNotLoaded returns a boolean indicating whether the error is a not loaded error. +func IsNotLoaded(err error) bool { + if err == nil { + return false + } + var e *NotLoadedError + return errors.As(err, &e) +} + +// ConstraintError returns when trying to create/update one or more entities and +// one or more of their constraints failed. For example, violation of edge or +// field uniqueness. +type ConstraintError struct { + msg string + wrap error +} + +// Error implements the error interface. +func (e ConstraintError) Error() string { + return "ent: constraint failed: " + e.msg +} + +// Unwrap implements the errors.Wrapper interface. +func (e *ConstraintError) Unwrap() error { + return e.wrap +} + +// IsConstraintError returns a boolean indicating whether the error is a constraint failure. +func IsConstraintError(err error) bool { + if err == nil { + return false + } + var e *ConstraintError + return errors.As(err, &e) +} + +func isSQLConstraintError(err error) (*ConstraintError, bool) { + var ( + msg = err.Error() + // error format per dialect. + errors = [...]string{ + "Error 1062", // MySQL 1062 error (ER_DUP_ENTRY). + "UNIQUE constraint failed", // SQLite. + "duplicate key value violates unique constraint", // PostgreSQL. + } + ) + if _, ok := err.(*sqlgraph.ConstraintError); ok { + return &ConstraintError{msg, err}, true + } + for i := range errors { + if strings.Contains(msg, errors[i]) { + return &ConstraintError{msg, err}, true + } + } + return nil, false +} + +// rollback calls tx.Rollback and wraps the given error with the rollback error if present. +func rollback(tx dialect.Tx, err error) error { + if rerr := tx.Rollback(); rerr != nil { + err = fmt.Errorf("%s: %v", err.Error(), rerr) + } + if err, ok := isSQLConstraintError(err); ok { + return err + } + return err +} diff --git a/ent/enttest/enttest.go b/ent/enttest/enttest.go new file mode 100644 index 0000000..f5beaf8 --- /dev/null +++ b/ent/enttest/enttest.go @@ -0,0 +1,77 @@ +// Code generated by entc, DO NOT EDIT. + +package enttest + +import ( + "context" + "github/four-servings/meonzi/ent" + // required by schema hooks. + _ "github/four-servings/meonzi/ent/runtime" + + "entgo.io/ent/dialect/sql/schema" +) + +type ( + // TestingT is the interface that is shared between + // testing.T and testing.B and used by enttest. + TestingT interface { + FailNow() + Error(...interface{}) + } + + // Option configures client creation. + Option func(*options) + + options struct { + opts []ent.Option + migrateOpts []schema.MigrateOption + } +) + +// WithOptions forwards options to client creation. +func WithOptions(opts ...ent.Option) Option { + return func(o *options) { + o.opts = append(o.opts, opts...) + } +} + +// WithMigrateOptions forwards options to auto migration. +func WithMigrateOptions(opts ...schema.MigrateOption) Option { + return func(o *options) { + o.migrateOpts = append(o.migrateOpts, opts...) + } +} + +func newOptions(opts []Option) *options { + o := &options{} + for _, opt := range opts { + opt(o) + } + return o +} + +// Open calls ent.Open and auto-run migration. +func Open(t TestingT, driverName, dataSourceName string, opts ...Option) *ent.Client { + o := newOptions(opts) + c, err := ent.Open(driverName, dataSourceName, o.opts...) + if err != nil { + t.Error(err) + t.FailNow() + } + if err := c.Schema.Create(context.Background(), o.migrateOpts...); err != nil { + t.Error(err) + t.FailNow() + } + return c +} + +// NewClient calls ent.NewClient and auto-run migration. +func NewClient(t TestingT, opts ...Option) *ent.Client { + o := newOptions(opts) + c := ent.NewClient(o.opts...) + if err := c.Schema.Create(context.Background(), o.migrateOpts...); err != nil { + t.Error(err) + t.FailNow() + } + return c +} diff --git a/ent/generate.go b/ent/generate.go new file mode 100644 index 0000000..9fdb106 --- /dev/null +++ b/ent/generate.go @@ -0,0 +1,3 @@ +package ent + +//go:generate go run entgo.io/ent/cmd/ent generate ./schema diff --git a/ent/hook/hook.go b/ent/hook/hook.go new file mode 100644 index 0000000..0e9da41 --- /dev/null +++ b/ent/hook/hook.go @@ -0,0 +1,203 @@ +// Code generated by entc, DO NOT EDIT. + +package hook + +import ( + "context" + "fmt" + "github/four-servings/meonzi/ent" +) + +// The AccountFunc type is an adapter to allow the use of ordinary +// function as Account mutator. +type AccountFunc func(context.Context, *ent.AccountMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f AccountFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + mv, ok := m.(*ent.AccountMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.AccountMutation", m) + } + return f(ctx, mv) +} + +// Condition is a hook condition function. +type Condition func(context.Context, ent.Mutation) bool + +// And groups conditions with the AND operator. +func And(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if !first(ctx, m) || !second(ctx, m) { + return false + } + for _, cond := range rest { + if !cond(ctx, m) { + return false + } + } + return true + } +} + +// Or groups conditions with the OR operator. +func Or(first, second Condition, rest ...Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + if first(ctx, m) || second(ctx, m) { + return true + } + for _, cond := range rest { + if cond(ctx, m) { + return true + } + } + return false + } +} + +// Not negates a given condition. +func Not(cond Condition) Condition { + return func(ctx context.Context, m ent.Mutation) bool { + return !cond(ctx, m) + } +} + +// HasOp is a condition testing mutation operation. +func HasOp(op ent.Op) Condition { + return func(_ context.Context, m ent.Mutation) bool { + return m.Op().Is(op) + } +} + +// HasAddedFields is a condition validating `.AddedField` on fields. +func HasAddedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.AddedField(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.AddedField(field); !exists { + return false + } + } + return true + } +} + +// HasClearedFields is a condition validating `.FieldCleared` on fields. +func HasClearedFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if exists := m.FieldCleared(field); !exists { + return false + } + for _, field := range fields { + if exists := m.FieldCleared(field); !exists { + return false + } + } + return true + } +} + +// HasFields is a condition validating `.Field` on fields. +func HasFields(field string, fields ...string) Condition { + return func(_ context.Context, m ent.Mutation) bool { + if _, exists := m.Field(field); !exists { + return false + } + for _, field := range fields { + if _, exists := m.Field(field); !exists { + return false + } + } + return true + } +} + +// If executes the given hook under condition. +// +// hook.If(ComputeAverage, And(HasFields(...), HasAddedFields(...))) +// +func If(hk ent.Hook, cond Condition) ent.Hook { + return func(next ent.Mutator) ent.Mutator { + return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if cond(ctx, m) { + return hk(next).Mutate(ctx, m) + } + return next.Mutate(ctx, m) + }) + } +} + +// On executes the given hook only for the given operation. +// +// hook.On(Log, ent.Delete|ent.Create) +// +func On(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, HasOp(op)) +} + +// Unless skips the given hook only for the given operation. +// +// hook.Unless(Log, ent.Update|ent.UpdateOne) +// +func Unless(hk ent.Hook, op ent.Op) ent.Hook { + return If(hk, Not(HasOp(op))) +} + +// FixedError is a hook returning a fixed error. +func FixedError(err error) ent.Hook { + return func(ent.Mutator) ent.Mutator { + return ent.MutateFunc(func(context.Context, ent.Mutation) (ent.Value, error) { + return nil, err + }) + } +} + +// Reject returns a hook that rejects all operations that match op. +// +// func (T) Hooks() []ent.Hook { +// return []ent.Hook{ +// Reject(ent.Delete|ent.Update), +// } +// } +// +func Reject(op ent.Op) ent.Hook { + hk := FixedError(fmt.Errorf("%s operation is not allowed", op)) + return On(hk, op) +} + +// Chain acts as a list of hooks and is effectively immutable. +// Once created, it will always hold the same set of hooks in the same order. +type Chain struct { + hooks []ent.Hook +} + +// NewChain creates a new chain of hooks. +func NewChain(hooks ...ent.Hook) Chain { + return Chain{append([]ent.Hook(nil), hooks...)} +} + +// Hook chains the list of hooks and returns the final hook. +func (c Chain) Hook() ent.Hook { + return func(mutator ent.Mutator) ent.Mutator { + for i := len(c.hooks) - 1; i >= 0; i-- { + mutator = c.hooks[i](mutator) + } + return mutator + } +} + +// Append extends a chain, adding the specified hook +// as the last ones in the mutation flow. +func (c Chain) Append(hooks ...ent.Hook) Chain { + newHooks := make([]ent.Hook, 0, len(c.hooks)+len(hooks)) + newHooks = append(newHooks, c.hooks...) + newHooks = append(newHooks, hooks...) + return Chain{newHooks} +} + +// Extend extends a chain, adding the specified chain +// as the last ones in the mutation flow. +func (c Chain) Extend(chain Chain) Chain { + return c.Append(chain.hooks...) +} diff --git a/ent/migrate/migrate.go b/ent/migrate/migrate.go new file mode 100644 index 0000000..0ce6a6e --- /dev/null +++ b/ent/migrate/migrate.go @@ -0,0 +1,72 @@ +// Code generated by entc, DO NOT EDIT. + +package migrate + +import ( + "context" + "fmt" + "io" + + "entgo.io/ent/dialect" + "entgo.io/ent/dialect/sql/schema" +) + +var ( + // WithGlobalUniqueID sets the universal ids options to the migration. + // If this option is enabled, ent migration will allocate a 1<<32 range + // for the ids of each entity (table). + // Note that this option cannot be applied on tables that already exist. + WithGlobalUniqueID = schema.WithGlobalUniqueID + // WithDropColumn sets the drop column option to the migration. + // If this option is enabled, ent migration will drop old columns + // that were used for both fields and edges. This defaults to false. + WithDropColumn = schema.WithDropColumn + // WithDropIndex sets the drop index option to the migration. + // If this option is enabled, ent migration will drop old indexes + // that were defined in the schema. This defaults to false. + // Note that unique constraints are defined using `UNIQUE INDEX`, + // and therefore, it's recommended to enable this option to get more + // flexibility in the schema changes. + WithDropIndex = schema.WithDropIndex + // WithFixture sets the foreign-key renaming option to the migration when upgrading + // ent from v0.1.0 (issue-#285). Defaults to false. + WithFixture = schema.WithFixture + // WithForeignKeys enables creating foreign-key in schema DDL. This defaults to true. + WithForeignKeys = schema.WithForeignKeys +) + +// Schema is the API for creating, migrating and dropping a schema. +type Schema struct { + drv dialect.Driver + universalID bool +} + +// NewSchema creates a new schema client. +func NewSchema(drv dialect.Driver) *Schema { return &Schema{drv: drv} } + +// Create creates all schema resources. +func (s *Schema) Create(ctx context.Context, opts ...schema.MigrateOption) error { + migrate, err := schema.NewMigrate(s.drv, opts...) + if err != nil { + return fmt.Errorf("ent/migrate: %v", err) + } + return migrate.Create(ctx, Tables...) +} + +// WriteTo writes the schema changes to w instead of running them against the database. +// +// if err := client.Schema.WriteTo(context.Background(), os.Stdout); err != nil { +// log.Fatal(err) +// } +// +func (s *Schema) WriteTo(ctx context.Context, w io.Writer, opts ...schema.MigrateOption) error { + drv := &schema.WriteDriver{ + Writer: w, + Driver: s.drv, + } + migrate, err := schema.NewMigrate(drv, opts...) + if err != nil { + return fmt.Errorf("ent/migrate: %v", err) + } + return migrate.Create(ctx, Tables...) +} diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go new file mode 100644 index 0000000..d2fde44 --- /dev/null +++ b/ent/migrate/schema.go @@ -0,0 +1,51 @@ +// Code generated by entc, DO NOT EDIT. + +package migrate + +import ( + "entgo.io/ent/dialect/entsql" + "entgo.io/ent/dialect/sql/schema" + "entgo.io/ent/schema/field" +) + +var ( + // AccountColumns holds the columns for the "account" table. + AccountColumns = []*schema.Column{ + {Name: "id", Type: field.TypeUUID}, + {Name: "social_type", Type: field.TypeUint8}, + {Name: "social_id", Type: field.TypeString, Size: 30}, + {Name: "name", Type: field.TypeString, Size: 30}, + {Name: "create_at", Type: field.TypeTime}, + {Name: "update_at", Type: field.TypeTime}, + {Name: "delete_at", Type: field.TypeTime, Nullable: true}, + } + // AccountTable holds the schema information for the "account" table. + AccountTable = &schema.Table{ + Name: "account", + Columns: AccountColumns, + PrimaryKey: []*schema.Column{AccountColumns[0]}, + ForeignKeys: []*schema.ForeignKey{}, + Indexes: []*schema.Index{ + { + Name: "account_social_type_social_id", + Unique: true, + Columns: []*schema.Column{AccountColumns[1], AccountColumns[2]}, + }, + { + Name: "account_delete_at", + Unique: false, + Columns: []*schema.Column{AccountColumns[6]}, + }, + }, + } + // Tables holds all the tables in the schema. + Tables = []*schema.Table{ + AccountTable, + } +) + +func init() { + AccountTable.Annotation = &entsql.Annotation{ + Table: "account", + } +} diff --git a/ent/mutation.go b/ent/mutation.go new file mode 100644 index 0000000..662a41b --- /dev/null +++ b/ent/mutation.go @@ -0,0 +1,649 @@ +// Code generated by entc, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "github/four-servings/meonzi/ent/account" + "github/four-servings/meonzi/ent/predicate" + "github/four-servings/meonzi/ent/schema" + "sync" + "time" + + "entgo.io/ent" + "github.com/google/uuid" +) + +const ( + // Operation types. + OpCreate = ent.OpCreate + OpDelete = ent.OpDelete + OpDeleteOne = ent.OpDeleteOne + OpUpdate = ent.OpUpdate + OpUpdateOne = ent.OpUpdateOne + + // Node types. + TypeAccount = "Account" +) + +// AccountMutation represents an operation that mutates the Account nodes in the graph. +type AccountMutation struct { + config + op Op + typ string + id *uuid.UUID + social_type *schema.SocialType + addsocial_type *schema.SocialType + social_id *string + name *string + create_at *time.Time + update_at *time.Time + delete_at *time.Time + clearedFields map[string]struct{} + done bool + oldValue func(context.Context) (*Account, error) + predicates []predicate.Account +} + +var _ ent.Mutation = (*AccountMutation)(nil) + +// accountOption allows management of the mutation configuration using functional options. +type accountOption func(*AccountMutation) + +// newAccountMutation creates new mutation for the Account entity. +func newAccountMutation(c config, op Op, opts ...accountOption) *AccountMutation { + m := &AccountMutation{ + config: c, + op: op, + typ: TypeAccount, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withAccountID sets the ID field of the mutation. +func withAccountID(id uuid.UUID) accountOption { + return func(m *AccountMutation) { + var ( + err error + once sync.Once + value *Account + ) + m.oldValue = func(ctx context.Context) (*Account, error) { + once.Do(func() { + if m.done { + err = fmt.Errorf("querying old values post mutation is not allowed") + } else { + value, err = m.Client().Account.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withAccount sets the old Account of the mutation. +func withAccount(node *Account) accountOption { + return func(m *AccountMutation) { + m.oldValue = func(context.Context) (*Account, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m AccountMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m AccountMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, fmt.Errorf("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// SetID sets the value of the id field. Note that this +// operation is only accepted on creation of Account entities. +func (m *AccountMutation) SetID(id uuid.UUID) { + m.id = &id +} + +// ID returns the ID value in the mutation. Note that the ID +// is only available if it was provided to the builder. +func (m *AccountMutation) ID() (id uuid.UUID, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// SetSocialType sets the "social_type" field. +func (m *AccountMutation) SetSocialType(st schema.SocialType) { + m.social_type = &st + m.addsocial_type = nil +} + +// SocialType returns the value of the "social_type" field in the mutation. +func (m *AccountMutation) SocialType() (r schema.SocialType, exists bool) { + v := m.social_type + if v == nil { + return + } + return *v, true +} + +// OldSocialType returns the old "social_type" field's value of the Account entity. +// If the Account object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AccountMutation) OldSocialType(ctx context.Context) (v schema.SocialType, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldSocialType is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldSocialType requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSocialType: %w", err) + } + return oldValue.SocialType, nil +} + +// AddSocialType adds st to the "social_type" field. +func (m *AccountMutation) AddSocialType(st schema.SocialType) { + if m.addsocial_type != nil { + *m.addsocial_type += st + } else { + m.addsocial_type = &st + } +} + +// AddedSocialType returns the value that was added to the "social_type" field in this mutation. +func (m *AccountMutation) AddedSocialType() (r schema.SocialType, exists bool) { + v := m.addsocial_type + if v == nil { + return + } + return *v, true +} + +// ResetSocialType resets all changes to the "social_type" field. +func (m *AccountMutation) ResetSocialType() { + m.social_type = nil + m.addsocial_type = nil +} + +// SetSocialID sets the "social_id" field. +func (m *AccountMutation) SetSocialID(s string) { + m.social_id = &s +} + +// SocialID returns the value of the "social_id" field in the mutation. +func (m *AccountMutation) SocialID() (r string, exists bool) { + v := m.social_id + if v == nil { + return + } + return *v, true +} + +// OldSocialID returns the old "social_id" field's value of the Account entity. +// If the Account object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AccountMutation) OldSocialID(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldSocialID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldSocialID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSocialID: %w", err) + } + return oldValue.SocialID, nil +} + +// ResetSocialID resets all changes to the "social_id" field. +func (m *AccountMutation) ResetSocialID() { + m.social_id = nil +} + +// SetName sets the "name" field. +func (m *AccountMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *AccountMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the Account entity. +// If the Account object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AccountMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ResetName resets all changes to the "name" field. +func (m *AccountMutation) ResetName() { + m.name = nil +} + +// SetCreateAt sets the "create_at" field. +func (m *AccountMutation) SetCreateAt(t time.Time) { + m.create_at = &t +} + +// CreateAt returns the value of the "create_at" field in the mutation. +func (m *AccountMutation) CreateAt() (r time.Time, exists bool) { + v := m.create_at + if v == nil { + return + } + return *v, true +} + +// OldCreateAt returns the old "create_at" field's value of the Account entity. +// If the Account object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AccountMutation) OldCreateAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldCreateAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldCreateAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldCreateAt: %w", err) + } + return oldValue.CreateAt, nil +} + +// ResetCreateAt resets all changes to the "create_at" field. +func (m *AccountMutation) ResetCreateAt() { + m.create_at = nil +} + +// SetUpdateAt sets the "update_at" field. +func (m *AccountMutation) SetUpdateAt(t time.Time) { + m.update_at = &t +} + +// UpdateAt returns the value of the "update_at" field in the mutation. +func (m *AccountMutation) UpdateAt() (r time.Time, exists bool) { + v := m.update_at + if v == nil { + return + } + return *v, true +} + +// OldUpdateAt returns the old "update_at" field's value of the Account entity. +// If the Account object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AccountMutation) OldUpdateAt(ctx context.Context) (v time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldUpdateAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldUpdateAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldUpdateAt: %w", err) + } + return oldValue.UpdateAt, nil +} + +// ResetUpdateAt resets all changes to the "update_at" field. +func (m *AccountMutation) ResetUpdateAt() { + m.update_at = nil +} + +// SetDeleteAt sets the "delete_at" field. +func (m *AccountMutation) SetDeleteAt(t time.Time) { + m.delete_at = &t +} + +// DeleteAt returns the value of the "delete_at" field in the mutation. +func (m *AccountMutation) DeleteAt() (r time.Time, exists bool) { + v := m.delete_at + if v == nil { + return + } + return *v, true +} + +// OldDeleteAt returns the old "delete_at" field's value of the Account entity. +// If the Account object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *AccountMutation) OldDeleteAt(ctx context.Context) (v *time.Time, err error) { + if !m.op.Is(OpUpdateOne) { + return v, fmt.Errorf("OldDeleteAt is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, fmt.Errorf("OldDeleteAt requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDeleteAt: %w", err) + } + return oldValue.DeleteAt, nil +} + +// ClearDeleteAt clears the value of the "delete_at" field. +func (m *AccountMutation) ClearDeleteAt() { + m.delete_at = nil + m.clearedFields[account.FieldDeleteAt] = struct{}{} +} + +// DeleteAtCleared returns if the "delete_at" field was cleared in this mutation. +func (m *AccountMutation) DeleteAtCleared() bool { + _, ok := m.clearedFields[account.FieldDeleteAt] + return ok +} + +// ResetDeleteAt resets all changes to the "delete_at" field. +func (m *AccountMutation) ResetDeleteAt() { + m.delete_at = nil + delete(m.clearedFields, account.FieldDeleteAt) +} + +// Op returns the operation name. +func (m *AccountMutation) Op() Op { + return m.op +} + +// Type returns the node type of this mutation (Account). +func (m *AccountMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *AccountMutation) Fields() []string { + fields := make([]string, 0, 6) + if m.social_type != nil { + fields = append(fields, account.FieldSocialType) + } + if m.social_id != nil { + fields = append(fields, account.FieldSocialID) + } + if m.name != nil { + fields = append(fields, account.FieldName) + } + if m.create_at != nil { + fields = append(fields, account.FieldCreateAt) + } + if m.update_at != nil { + fields = append(fields, account.FieldUpdateAt) + } + if m.delete_at != nil { + fields = append(fields, account.FieldDeleteAt) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *AccountMutation) Field(name string) (ent.Value, bool) { + switch name { + case account.FieldSocialType: + return m.SocialType() + case account.FieldSocialID: + return m.SocialID() + case account.FieldName: + return m.Name() + case account.FieldCreateAt: + return m.CreateAt() + case account.FieldUpdateAt: + return m.UpdateAt() + case account.FieldDeleteAt: + return m.DeleteAt() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *AccountMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case account.FieldSocialType: + return m.OldSocialType(ctx) + case account.FieldSocialID: + return m.OldSocialID(ctx) + case account.FieldName: + return m.OldName(ctx) + case account.FieldCreateAt: + return m.OldCreateAt(ctx) + case account.FieldUpdateAt: + return m.OldUpdateAt(ctx) + case account.FieldDeleteAt: + return m.OldDeleteAt(ctx) + } + return nil, fmt.Errorf("unknown Account field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *AccountMutation) SetField(name string, value ent.Value) error { + switch name { + case account.FieldSocialType: + v, ok := value.(schema.SocialType) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSocialType(v) + return nil + case account.FieldSocialID: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSocialID(v) + return nil + case account.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil + case account.FieldCreateAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetCreateAt(v) + return nil + case account.FieldUpdateAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetUpdateAt(v) + return nil + case account.FieldDeleteAt: + v, ok := value.(time.Time) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDeleteAt(v) + return nil + } + return fmt.Errorf("unknown Account field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *AccountMutation) AddedFields() []string { + var fields []string + if m.addsocial_type != nil { + fields = append(fields, account.FieldSocialType) + } + return fields +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *AccountMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case account.FieldSocialType: + return m.AddedSocialType() + } + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *AccountMutation) AddField(name string, value ent.Value) error { + switch name { + case account.FieldSocialType: + v, ok := value.(schema.SocialType) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddSocialType(v) + return nil + } + return fmt.Errorf("unknown Account numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *AccountMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(account.FieldDeleteAt) { + fields = append(fields, account.FieldDeleteAt) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *AccountMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *AccountMutation) ClearField(name string) error { + switch name { + case account.FieldDeleteAt: + m.ClearDeleteAt() + return nil + } + return fmt.Errorf("unknown Account nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *AccountMutation) ResetField(name string) error { + switch name { + case account.FieldSocialType: + m.ResetSocialType() + return nil + case account.FieldSocialID: + m.ResetSocialID() + return nil + case account.FieldName: + m.ResetName() + return nil + case account.FieldCreateAt: + m.ResetCreateAt() + return nil + case account.FieldUpdateAt: + m.ResetUpdateAt() + return nil + case account.FieldDeleteAt: + m.ResetDeleteAt() + return nil + } + return fmt.Errorf("unknown Account field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *AccountMutation) AddedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *AccountMutation) AddedIDs(name string) []ent.Value { + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *AccountMutation) RemovedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *AccountMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *AccountMutation) ClearedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *AccountMutation) EdgeCleared(name string) bool { + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *AccountMutation) ClearEdge(name string) error { + return fmt.Errorf("unknown Account unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *AccountMutation) ResetEdge(name string) error { + return fmt.Errorf("unknown Account edge %s", name) +} diff --git a/ent/predicate/predicate.go b/ent/predicate/predicate.go new file mode 100644 index 0000000..a2148e0 --- /dev/null +++ b/ent/predicate/predicate.go @@ -0,0 +1,10 @@ +// Code generated by entc, DO NOT EDIT. + +package predicate + +import ( + "entgo.io/ent/dialect/sql" +) + +// Account is the predicate function for account builders. +type Account func(*sql.Selector) diff --git a/ent/runtime.go b/ent/runtime.go new file mode 100644 index 0000000..a60f01f --- /dev/null +++ b/ent/runtime.go @@ -0,0 +1,35 @@ +// Code generated by entc, DO NOT EDIT. + +package ent + +import ( + "github/four-servings/meonzi/ent/account" + "github/four-servings/meonzi/ent/schema" + "time" +) + +// The init function reads all schema descriptors with runtime code +// (default values, validators, hooks and policies) and stitches it +// to their package variables. +func init() { + accountFields := schema.Account{}.Fields() + _ = accountFields + // accountDescSocialID is the schema descriptor for social_id field. + accountDescSocialID := accountFields[2].Descriptor() + // account.SocialIDValidator is a validator for the "social_id" field. It is called by the builders before save. + account.SocialIDValidator = accountDescSocialID.Validators[0].(func(string) error) + // accountDescName is the schema descriptor for name field. + accountDescName := accountFields[3].Descriptor() + // account.NameValidator is a validator for the "name" field. It is called by the builders before save. + account.NameValidator = accountDescName.Validators[0].(func(string) error) + // accountDescCreateAt is the schema descriptor for create_at field. + accountDescCreateAt := accountFields[4].Descriptor() + // account.DefaultCreateAt holds the default value on creation for the create_at field. + account.DefaultCreateAt = accountDescCreateAt.Default.(func() time.Time) + // accountDescUpdateAt is the schema descriptor for update_at field. + accountDescUpdateAt := accountFields[5].Descriptor() + // account.DefaultUpdateAt holds the default value on creation for the update_at field. + account.DefaultUpdateAt = accountDescUpdateAt.Default.(func() time.Time) + // account.UpdateDefaultUpdateAt holds the default value on update for the update_at field. + account.UpdateDefaultUpdateAt = accountDescUpdateAt.UpdateDefault.(func() time.Time) +} diff --git a/ent/runtime/runtime.go b/ent/runtime/runtime.go new file mode 100644 index 0000000..ea840e2 --- /dev/null +++ b/ent/runtime/runtime.go @@ -0,0 +1,10 @@ +// Code generated by entc, DO NOT EDIT. + +package runtime + +// The schema-stitching logic is generated in github/four-servings/meonzi/ent/runtime.go + +const ( + Version = "v0.6.0" // Version of ent codegen. + Sum = "h1:oo/a8sXPQKzHYFlVwmwOnyzBy+u8FWQsoLLqFCrOBt0=" // Sum of ent codegen. +) diff --git a/ent/schema/account.go b/ent/schema/account.go new file mode 100644 index 0000000..97b7969 --- /dev/null +++ b/ent/schema/account.go @@ -0,0 +1,95 @@ +package schema + +import ( + "entgo.io/ent/dialect/entsql" + "entgo.io/ent/schema" + "strings" + "time" + + "entgo.io/ent" + "entgo.io/ent/schema/field" + "entgo.io/ent/schema/index" + "github.com/google/uuid" +) + +// Account holds the schema definition for the Account entity. +type Account struct { + ent.Schema +} + +type SocialType uint8 + +const ( + SocialTypeUnknown SocialType = iota + SocialTypeKakao + SocialTypeGoogle +) + +var ( + socialTypeToString = []string{ + "unknown", + "kakao", + "google", + } + + socialTypeFromString = map[string]SocialType{ + "kakao": SocialTypeKakao, + "google": SocialTypeGoogle, + } +) + +func (s SocialType) String() string { + if len(socialTypeToString) <= int(s) { + return "unknown" + } + + return socialTypeToString[int(s)] +} + +func (s SocialType) MarshalJSON() ([]byte, error) { + return []byte("\"" + s.String() + "\""), nil +} + +func (s *SocialType) UnmarshalJSON(data []byte) error { + v, ok := socialTypeFromString[strings.Trim(string(data), "\"")] + if !ok { + *s = SocialTypeUnknown + } else { + *s = v + } + + return nil +} + +// domain model, orm => database entity + +// Fields of the Account. +func (Account) Fields() []ent.Field { + return []ent.Field{ + field.UUID("id", uuid.UUID{}).Immutable(), + field.Uint8("social_type").GoType(SocialTypeUnknown).Immutable(), + field.String("social_id").MaxLen(30).Immutable(), + field.String("name").MaxLen(30), + field.Time("create_at").Default(time.Now).Immutable(), + field.Time("update_at").Default(time.Now).UpdateDefault(time.Now), + field.Time("delete_at").Optional().Nillable(), + } +} + +func (Account) Indexes() []ent.Index { + return []ent.Index{ + index.Fields("social_type", "social_id").Unique(), + index.Fields("delete_at"), + } +} + +// Edges of the Account. +func (Account) Edges() []ent.Edge { + return nil +} + +func (Account) Annotations() []schema.Annotation { + return []schema.Annotation{ + entsql.Annotation{Table: "account"}, + } +} diff --git a/ent/tx.go b/ent/tx.go new file mode 100644 index 0000000..8457505 --- /dev/null +++ b/ent/tx.go @@ -0,0 +1,210 @@ +// Code generated by entc, DO NOT EDIT. + +package ent + +import ( + "context" + "sync" + + "entgo.io/ent/dialect" +) + +// Tx is a transactional client that is created by calling Client.Tx(). +type Tx struct { + config + // Account is the client for interacting with the Account builders. + Account *AccountClient + + // lazily loaded. + client *Client + clientOnce sync.Once + + // completion callbacks. + mu sync.Mutex + onCommit []CommitHook + onRollback []RollbackHook + + // ctx lives for the life of the transaction. It is + // the same context used by the underlying connection. + ctx context.Context +} + +type ( + // Committer is the interface that wraps the Committer method. + Committer interface { + Commit(context.Context, *Tx) error + } + + // The CommitFunc type is an adapter to allow the use of ordinary + // function as a Committer. If f is a function with the appropriate + // signature, CommitFunc(f) is a Committer that calls f. + CommitFunc func(context.Context, *Tx) error + + // CommitHook defines the "commit middleware". A function that gets a Committer + // and returns a Committer. For example: + // + // hook := func(next ent.Committer) ent.Committer { + // return ent.CommitFunc(func(context.Context, tx *ent.Tx) error { + // // Do some stuff before. + // if err := next.Commit(ctx, tx); err != nil { + // return err + // } + // // Do some stuff after. + // return nil + // }) + // } + // + CommitHook func(Committer) Committer +) + +// Commit calls f(ctx, m). +func (f CommitFunc) Commit(ctx context.Context, tx *Tx) error { + return f(ctx, tx) +} + +// Commit commits the transaction. +func (tx *Tx) Commit() error { + txDriver := tx.config.driver.(*txDriver) + var fn Committer = CommitFunc(func(context.Context, *Tx) error { + return txDriver.tx.Commit() + }) + tx.mu.Lock() + hooks := append([]CommitHook(nil), tx.onCommit...) + tx.mu.Unlock() + for i := len(hooks) - 1; i >= 0; i-- { + fn = hooks[i](fn) + } + return fn.Commit(tx.ctx, tx) +} + +// OnCommit adds a hook to call on commit. +func (tx *Tx) OnCommit(f CommitHook) { + tx.mu.Lock() + defer tx.mu.Unlock() + tx.onCommit = append(tx.onCommit, f) +} + +type ( + // Rollbacker is the interface that wraps the Rollbacker method. + Rollbacker interface { + Rollback(context.Context, *Tx) error + } + + // The RollbackFunc type is an adapter to allow the use of ordinary + // function as a Rollbacker. If f is a function with the appropriate + // signature, RollbackFunc(f) is a Rollbacker that calls f. + RollbackFunc func(context.Context, *Tx) error + + // RollbackHook defines the "rollback middleware". A function that gets a Rollbacker + // and returns a Rollbacker. For example: + // + // hook := func(next ent.Rollbacker) ent.Rollbacker { + // return ent.RollbackFunc(func(context.Context, tx *ent.Tx) error { + // // Do some stuff before. + // if err := next.Rollback(ctx, tx); err != nil { + // return err + // } + // // Do some stuff after. + // return nil + // }) + // } + // + RollbackHook func(Rollbacker) Rollbacker +) + +// Rollback calls f(ctx, m). +func (f RollbackFunc) Rollback(ctx context.Context, tx *Tx) error { + return f(ctx, tx) +} + +// Rollback rollbacks the transaction. +func (tx *Tx) Rollback() error { + txDriver := tx.config.driver.(*txDriver) + var fn Rollbacker = RollbackFunc(func(context.Context, *Tx) error { + return txDriver.tx.Rollback() + }) + tx.mu.Lock() + hooks := append([]RollbackHook(nil), tx.onRollback...) + tx.mu.Unlock() + for i := len(hooks) - 1; i >= 0; i-- { + fn = hooks[i](fn) + } + return fn.Rollback(tx.ctx, tx) +} + +// OnRollback adds a hook to call on rollback. +func (tx *Tx) OnRollback(f RollbackHook) { + tx.mu.Lock() + defer tx.mu.Unlock() + tx.onRollback = append(tx.onRollback, f) +} + +// Client returns a Client that binds to current transaction. +func (tx *Tx) Client() *Client { + tx.clientOnce.Do(func() { + tx.client = &Client{config: tx.config} + tx.client.init() + }) + return tx.client +} + +func (tx *Tx) init() { + tx.Account = NewAccountClient(tx.config) +} + +// txDriver wraps the given dialect.Tx with a nop dialect.Driver implementation. +// The idea is to support transactions without adding any extra code to the builders. +// When a builder calls to driver.Tx(), it gets the same dialect.Tx instance. +// Commit and Rollback are nop for the internal builders and the user must call one +// of them in order to commit or rollback the transaction. +// +// If a closed transaction is embedded in one of the generated entities, and the entity +// applies a query, for example: Account.QueryXXX(), the query will be executed +// through the driver which created this transaction. +// +// Note that txDriver is not goroutine safe. +type txDriver struct { + // the driver we started the transaction from. + drv dialect.Driver + // tx is the underlying transaction. + tx dialect.Tx +} + +// newTx creates a new transactional driver. +func newTx(ctx context.Context, drv dialect.Driver) (*txDriver, error) { + tx, err := drv.Tx(ctx) + if err != nil { + return nil, err + } + return &txDriver{tx: tx, drv: drv}, nil +} + +// Tx returns the transaction wrapper (txDriver) to avoid Commit or Rollback calls +// from the internal builders. Should be called only by the internal builders. +func (tx *txDriver) Tx(context.Context) (dialect.Tx, error) { return tx, nil } + +// Dialect returns the dialect of the driver we started the transaction from. +func (tx *txDriver) Dialect() string { return tx.drv.Dialect() } + +// Close is a nop close. +func (*txDriver) Close() error { return nil } + +// Commit is a nop commit for the internal builders. +// User must call `Tx.Commit` in order to commit the transaction. +func (*txDriver) Commit() error { return nil } + +// Rollback is a nop rollback for the internal builders. +// User must call `Tx.Rollback` in order to rollback the transaction. +func (*txDriver) Rollback() error { return nil } + +// Exec calls tx.Exec. +func (tx *txDriver) Exec(ctx context.Context, query string, args, v interface{}) error { + return tx.tx.Exec(ctx, query, args, v) +} + +// Query calls tx.Query. +func (tx *txDriver) Query(ctx context.Context, query string, args, v interface{}) error { + return tx.tx.Query(ctx, query, args, v) +} + +var _ dialect.Driver = (*txDriver)(nil) diff --git a/generate.sh b/generate.sh new file mode 100644 index 0000000..009c43d --- /dev/null +++ b/generate.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +go generate . +go generate ./ent \ No newline at end of file diff --git a/go.mod b/go.mod index b8c8567..862cfe0 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,20 @@ module github/four-servings/meonzi go 1.15 require ( - github.com/google/uuid v1.1.2 - gorm.io/driver/mysql v1.0.3 - gorm.io/gorm v1.20.7 + entgo.io/ent v0.6.0 + github.com/caarlos0/env/v6 v6.5.0 + github.com/dgrijalva/jwt-go v3.2.0+incompatible + github.com/go-playground/validator/v10 v10.4.1 + github.com/go-sql-driver/mysql v1.5.1-0.20200311113236-681ffa848bae + github.com/google/uuid v1.2.0 + github.com/google/wire v0.5.0 + github.com/kr/text v0.2.0 // indirect + github.com/labstack/echo/v4 v4.2.0 + github.com/magefile/mage v1.11.0 // indirect + github.com/sirupsen/logrus v1.8.0 + golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb + golang.org/x/sync v0.0.0-20210220032951-036812b2e83c + golang.org/x/sys v0.0.0-20210303074136-134d130e1a04 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum deleted file mode 100644 index 61a38ad..0000000 --- a/go.sum +++ /dev/null @@ -1,13 +0,0 @@ -github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E= -github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -gorm.io/driver/mysql v1.0.3 h1:+JKBYPfn1tygR1/of/Fh2T8iwuVwzt+PEJmKaXzMQXg= -gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI= -gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.20.7 h1:rMS4CL3pNmYq1V5/X+nHHjh1Dx6dnf27+Cai5zabo+M= -gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= diff --git a/main.go b/main.go index bc8b056..d60bead 100644 --- a/main.go +++ b/main.go @@ -1,12 +1,9 @@ package main -import ( - _ "github/four-servings/meonzi/account" - "log" - "net/http" -) +import log "github.com/sirupsen/logrus" func main() { - log.Println("app is listening on port 5000") - http.ListenAndServe(":5000", nil) + log.SetFormatter(&log.JSONFormatter{}) + log.SetReportCaller(true) + GetApp().Start() } diff --git a/pipe/bus.go b/pipe/bus.go new file mode 100644 index 0000000..6d25476 --- /dev/null +++ b/pipe/bus.go @@ -0,0 +1,201 @@ +package pipe + +import ( + "context" + "errors" + "reflect" + "sync" + "time" +) + +var ( + contextType = reflect.TypeOf(new(context.Context)).Elem() + errorType = reflect.TypeOf(new(error)).Elem() +) + +type ExecuteError interface { + Error() error +} + +type executeErrorImpl struct { + err error +} + +func (e *executeErrorImpl) Error() error { + return e.err +} + +func newExecuteError(err error) ExecuteError { + return &executeErrorImpl{err} +} + +type ExecuteResult interface { + ExecuteError + Result(dst interface{}) ExecuteError +} + +type executeResultImpl struct { + ExecuteError + value interface{} +} + +func (e *executeResultImpl) Result(dst interface{}) ExecuteError { + destination := reflect.ValueOf(dst) + source := reflect.ValueOf(e.value) + + if reflect.New(source.Type()).Type() != destination.Type() { + return newExecuteError(errors.New("destination type not match to source type")) + } + + destination.Elem().Set(source) + return e.ExecuteError +} + +func newExecuteResult(value interface{}, err error) ExecuteResult { + return &executeResultImpl{ + ExecuteError: newExecuteError(err), + value: value, + } +} + +type BusHandlerFunc func(ctx context.Context, value interface{}) (interface{}, error) + +type BusHandler interface { + Wrap() BusHandlerFunc +} + +type Bus interface { + RegistryStrictHandler(targetType interface{}, handler BusHandler) error + RegistryHandler(targetType interface{}, handler interface{}) error + Execute(value interface{}) ExecuteResult + ExecuteContext(ctx context.Context, value interface{}) ExecuteResult +} + +type busImpl struct { + lock sync.RWMutex + gateway map[reflect.Type]BusHandlerFunc + timeout *time.Duration +} + +func NewBus() Bus { + return &busImpl{ + gateway: make(map[reflect.Type]BusHandlerFunc), + } +} + +func NewBusWithTimeout(timeout time.Duration) Bus { + return &busImpl{ + gateway: make(map[reflect.Type]BusHandlerFunc), + timeout: &timeout, + } +} + +func (b *busImpl) RegistryHandler(targetType interface{}, handler interface{}) error { + typ := reflect.TypeOf(targetType) + if b.exists(typ) { + return errors.New("already registry value") + } + + action := reflect.ValueOf(handler) + actionType := action.Type() + inCount := actionType.NumIn() + outCount := actionType.NumOut() + + if action.Kind() != reflect.Func { + //TODO error message + return errors.New("") + } + + if inCount > 2 { + return errors.New("handler call arguments count overflow") + } else if inCount == 2 && (contextType != actionType.In(0) || typ != actionType.In(1)) { + //TODO error message + return errors.New("") + } else if inCount == 1 && typ != actionType.In(0) { + //TODO error message + return errors.New("") + } + + if outCount > 2 { + return errors.New("handler call returns count overflow") + } else if outCount == 2 && !actionType.Out(1).Implements(errorType) { + //TODO error message + return errors.New("") + } else if outCount == 1 && !actionType.Out(0).Implements(errorType) { + return errors.New("handler call return must be error") + } + + b.set(typ, func(ctx context.Context, value interface{}) (ret interface{}, err error) { + in := make([]reflect.Value, inCount) + + switch inCount { + case 2: + in[0] = reflect.ValueOf(ctx) + in[1] = reflect.ValueOf(value) + case 1: + in[0] = reflect.ValueOf(value) + } + + out := action.Call(in) + switch outCount { + case 2: + ret = out[0].Interface() + err, _ = out[1].Interface().(error) + case 1: + err, _ = out[0].Interface().(error) + } + return + }) + return nil +} + +func (b *busImpl) RegistryStrictHandler(targetType interface{}, handler BusHandler) error { + typ := reflect.TypeOf(targetType) + if b.exists(typ) { + return errors.New("already registry value") + } + + b.set(typ, handler.Wrap()) + return nil +} + +func (b *busImpl) Execute(value interface{}) ExecuteResult { + return b.ExecuteContext(context.Background(), value) +} + +func (b *busImpl) ExecuteContext(ctx context.Context, value interface{}) ExecuteResult { + c := ctx + if b.timeout != nil { + var cancel context.CancelFunc + c, cancel = context.WithTimeout(ctx, *b.timeout) + defer cancel() + } + + typ := reflect.TypeOf(value) + handle, ok := b.get(typ) + if !ok { + return newExecuteResult(nil, errors.New("handler not exists")) + } + return newExecuteResult(handle(c, value)) +} + +// critical section method +func (b *busImpl) set(typ reflect.Type, handler BusHandlerFunc) { + b.lock.Lock() + defer b.lock.Unlock() + b.gateway[typ] = handler +} + +func (b *busImpl) get(typ reflect.Type) (handler BusHandlerFunc, ok bool) { + b.lock.RLock() + defer b.lock.RUnlock() + handler, ok = b.gateway[typ] + return +} + +func (b *busImpl) exists(typ reflect.Type) (ok bool) { + b.lock.RLock() + defer b.lock.RUnlock() + _, ok = b.gateway[typ] + return +} diff --git a/pipe/pubsub.go b/pipe/pubsub.go new file mode 100644 index 0000000..03d19f8 --- /dev/null +++ b/pipe/pubsub.go @@ -0,0 +1,186 @@ +package pipe + +import ( + "errors" + "reflect" + "sync" +) + +type PubSub interface { + Publish(value interface{}) + Subscribe(handler interface{}) error +} + +//TODO exists check +type subs struct { + lock sync.RWMutex + handler []interface{} +} + +func (s *subs) mux(value interface{}) { + s.lock.RLock() + defer s.lock.RUnlock() + for i := range s.handler { + action := reflect.ValueOf(s.handler[i]) + go action.Call([]reflect.Value{reflect.ValueOf(value)}) + } +} + +func (s *subs) append(handler interface{}) { + s.lock.Lock() + defer s.lock.Unlock() + s.handler = append(s.handler, handler) +} + +type values struct { + lock sync.RWMutex + value []interface{} +} + +func (v *values) append(value ...interface{}) { + v.lock.Lock() + defer v.lock.Unlock() + v.value = append(v.value, value...) +} + +func (v *values) get(i int) (res interface{}) { + v.lock.RLock() + defer v.lock.RUnlock() + res = v.value[i] + return +} + +func (v *values) count() (cnt int) { + v.lock.RLock() + defer v.lock.RUnlock() + cnt = len(v.value) + return +} + +// TODO max value count +type pubsubImpl struct { + valueLock sync.RWMutex + value map[reflect.Type]*values + + subLock sync.RWMutex + sub map[reflect.Type]*subs +} + +func NewPubSub() PubSub { + return &pubsubImpl{ + value: make(map[reflect.Type]*values), + sub: make(map[reflect.Type]*subs), + } +} + +func (ps *pubsubImpl) Publish(value interface{}) { + go ps.appendValue(value) + go ps.callSubscribers(value) +} + +func (ps *pubsubImpl) Subscribe(handler interface{}) error { + return ps.appendSub(handler) +} + +// critical section +func (ps *pubsubImpl) callSubscribers(value interface{}) { + typ := reflect.TypeOf(value) + + ps.getSafeSubs(typ). + mux(value) +} + +func (ps *pubsubImpl) appendSub(handler interface{}) error { + handlerType := reflect.TypeOf(handler) + if handlerType.Kind() != reflect.Func { + //TODO error message + return errors.New("") + } else if handlerType.NumIn() != 1 { + //TODO error message + return errors.New("") + } + + typ := handlerType.In(0) + + sub := ps.getSafeSubs(typ) + val := ps.getSafeValues(typ) + seek := 0 + action := reflect.ValueOf(handler) + for seek < val.count() { + action.Call([]reflect.Value{reflect.ValueOf(val.get(seek))}) + seek++ + } + sub.append(handler) + return nil +} + +func (ps *pubsubImpl) getSafeSubs(typ reflect.Type) (res *subs) { + if ps.existsSubs(typ) { + res = ps.getSubs(typ) + } else { + res = ps.createSubs(typ) + } + + return +} + +func (ps *pubsubImpl) existsSubs(typ reflect.Type) (ok bool) { + ps.subLock.RLock() + defer ps.subLock.RUnlock() + _, ok = ps.sub[typ] + return +} + +func (ps *pubsubImpl) getSubs(typ reflect.Type) (res *subs) { + ps.subLock.RLock() + defer ps.subLock.RUnlock() + res = ps.sub[typ] + return +} + +func (ps *pubsubImpl) createSubs(typ reflect.Type) (res *subs) { + res = &subs{} + ps.subLock.Lock() + defer ps.subLock.Unlock() + ps.sub[typ] = res + return +} + +func (ps *pubsubImpl) appendValue(value interface{}) { + typ := reflect.TypeOf(value) + + ps.getSafeValues(typ). + append(value) +} + +func (ps *pubsubImpl) getSafeValues(typ reflect.Type) (res *values) { + if ps.existsValues(typ) { + res = ps.getValues(typ) + } else { + res = ps.createValues(typ) + } + + return +} + +func (ps *pubsubImpl) existsValues(typ reflect.Type) (ok bool) { + ps.valueLock.RLock() + defer ps.valueLock.RUnlock() + _, ok = ps.value[typ] + return +} + +func (ps *pubsubImpl) getValues(typ reflect.Type) (res *values) { + ps.valueLock.RLock() + defer ps.valueLock.RUnlock() + res = ps.value[typ] + return +} + +func (ps *pubsubImpl) createValues(typ reflect.Type) (res *values) { + res = &values{} + ps.valueLock.Lock() + defer ps.valueLock.Unlock() + ps.value[typ] = res + return +} diff --git a/setup/database.go b/setup/database.go deleted file mode 100644 index b69118d..0000000 --- a/setup/database.go +++ /dev/null @@ -1,43 +0,0 @@ -package setup - -import ( - "github/four-servings/meonzi/config" - "log" - "os" - "time" - - "gorm.io/driver/mysql" - "gorm.io/gorm" - "gorm.io/gorm/logger" -) - -// GetDatabaseConnection get database connection -func GetDatabaseConnection() *gorm.DB { - dbConfig := config.Database{} - - user := dbConfig.User() - password := dbConfig.Password() - host := dbConfig.Host() - port := dbConfig.Port() - name := dbConfig.Name() - - dsn := user + ":" + password + "@tcp(" + host + ":" + port + ")/" + name + "?parseTime=true" - - connection, err := gorm.Open( - mysql.Open(dsn), - &gorm.Config{ - Logger: logger.New( - log.New(os.Stdout, "\r\n", log.LstdFlags), - logger.Config{ - SlowThreshold: time.Second, - LogLevel: logger.Silent, - }, - ), - }, - ) - if err != nil { - panic(err) - } - - return connection -} diff --git a/util/arr/flatten.go b/util/arr/flatten.go new file mode 100644 index 0000000..fd692f1 --- /dev/null +++ b/util/arr/flatten.go @@ -0,0 +1,25 @@ +package arr + +import "reflect" + +func Flatten(args ...interface{}) (res []interface{}) { + return flatten(reflect.ValueOf(args)) +} + +func flatten(args reflect.Value) (res []interface{}) { + for idx, l := 0, args.Len(); idx < l; idx++ { + val := args.Index(idx) + kind := val.Kind() + if kind == reflect.Interface { + val = val.Elem() + kind = val.Kind() + } + if kind == reflect.Array || kind == reflect.Slice { + res = append(res, flatten(val)...) + } else { + res = append(res, val.Interface()) + } + } + + return +} diff --git a/util/imgutil/decoder.go b/util/imgutil/decoder.go new file mode 100644 index 0000000..ffc0fe1 --- /dev/null +++ b/util/imgutil/decoder.go @@ -0,0 +1,31 @@ +package imgutil + +import ( + "fmt" + "golang.org/x/image/bmp" + "golang.org/x/image/webp" + "image" + "image/gif" + "image/jpeg" + "image/png" + "io" +) + +func GetDecoder(mimeType string) func(io.Reader) (image.Image, error) { + switch mimeType { + case "image/jpeg": + return jpeg.Decode + case "image/png": + return png.Decode + case "image/bmp": + return bmp.Decode + case "image/gif": + return gif.Decode + case "image/webp": + return webp.Decode + } + + return func(_ io.Reader) (image.Image, error) { + return nil, fmt.Errorf("%s, mime type not supported", mimeType) + } +} \ No newline at end of file diff --git a/util/pointer/builtin.go b/util/pointer/builtin.go new file mode 100644 index 0000000..e111973 --- /dev/null +++ b/util/pointer/builtin.go @@ -0,0 +1,61 @@ +package pointer + +import ( + "time" +) + +func Time(t time.Time) *time.Time { + return &t +} + +func String(s string) *string { + return &s +} + +func Int(i int) *int { + return &i +} + +func Int8(i int8) *int8 { + return &i +} + +func Int16(i int16) *int16 { + return &i +} + +func Int32(i int32) *int32 { + return &i +} + +func Int64(i int64) *int64 { + return &i +} + +func Uint(ui uint) *uint { + return &ui +} + +func Uint8(ui uint8) *uint8 { + return &ui +} + +func Uint16(ui uint16) *uint16 { + return &ui +} + +func Uint32(ui uint32) *uint32 { + return &ui +} + +func Uint64(ui uint64) *uint64 { + return &ui +} + +func Float32(f float32) *float32 { + return &f +} + +func Float64(f float64) *float64 { + return &f +} \ No newline at end of file diff --git a/util/safe/default.go b/util/safe/default.go new file mode 100644 index 0000000..74719e7 --- /dev/null +++ b/util/safe/default.go @@ -0,0 +1,101 @@ +package safe + +import "time" + +func TimeOrDefault(t *time.Time, def time.Time) time.Time { + if t == nil { + return def + } + return *t +} + +func StringOrDefault(s *string, def string) string { + if s == nil { + return def + } + return *s +} + +func IntOrDefault(i *int, def int) int { + if i == nil { + return def + } + return *i +} + +func Int8OrDefault(i *int8, def int8) int8 { + if i == nil { + return def + } + return *i +} + +func Int16OrDefault(i *int16, def int16) int16 { + if i == nil { + return def + } + return *i +} + +func Int32OrDefault(i *int32, def int32) int32 { + if i == nil { + return def + } + return *i +} + +func Int64OrDefault(i *int64, def int64) int64 { + if i == nil { + return def + } + return *i +} + +func UintOrDefault(i *uint, def uint) uint { + if i == nil { + return def + } + return *i +} + +func Uint8OrDefault(i *uint8, def uint8) uint8 { + if i == nil { + return def + } + return *i +} + +func Uint16OrDefault(i *uint16, def uint16) uint16 { + if i == nil { + return def + } + return *i +} + +func Uint32OrDefault(i *uint32, def uint32) uint32 { + if i == nil { + return def + } + return *i +} + +func Uint64OrDefault(i *uint64, def uint64) uint64 { + if i == nil { + return def + } + return *i +} + +func Float32OrDefault(f *float32, def float32) float32 { + if f == nil { + return def + } + return *f +} + +func Float64OrDefault(f *float64, def float64) float64 { + if f == nil { + return def + } + return *f +} \ No newline at end of file diff --git a/wire.go b/wire.go new file mode 100644 index 0000000..9b30eab --- /dev/null +++ b/wire.go @@ -0,0 +1,27 @@ +//+build wireinject + +package main + +import ( + "github.com/google/wire" + "github/four-servings/meonzi/app" + "github/four-servings/meonzi/di" + "time" +) + +//func exampleGetAccountRepository() domain.AccountRepository { +// wire.Build(di.ConfigSets) +// return nil +//} + +func GetApp() *app.App { + wire.Build( + di.ProviderSets, + di.InfraSets, + wire.Value(time.Second * 3), + di.CommandBusSets, + di.ControllerSets, + di.RouteSets, + app.AppSets) + return nil +} \ No newline at end of file diff --git a/wire_gen.go b/wire_gen.go new file mode 100644 index 0000000..72a28ac --- /dev/null +++ b/wire_gen.go @@ -0,0 +1,42 @@ +// Code generated by Wire. DO NOT EDIT. + +//go:generate go run github.com/google/wire/cmd/wire +//+build !wireinject + +package main + +import ( + app2 "github/four-servings/meonzi/account/app" + "github/four-servings/meonzi/account/infra" + "github/four-servings/meonzi/account/interfaces" + "github/four-servings/meonzi/app" + "github/four-servings/meonzi/di" + "time" +) + +// Injectors from wire.go: + +func GetApp() *app.App { + dbConn := app.GetDBConn() + client := di.ProviderDatabase(dbConn) + echo := di.ProviderEcho() + accountClient := di.ProviderAccountTable(client) + accountRepository := infra.NewAccountRepository(accountClient) + googleAdapter := infra.NewGoogleAdapter() + kakaoAdapter := infra.NewKakaoAdapter() + socialService := infra.NewSocialService(googleAdapter, kakaoAdapter) + duration := _wireDurationValue + commandBus := app2.NewCommandBus(accountRepository, socialService, duration) + validate := di.ProviderValidator() + authService := infra.NewAuthService() + controller := interfaces.NewAccountController(commandBus, validate, authService) + routing := infra.NewRoute(echo, controller) + setRoute := app.Routing(routing) + appApp := app.NewApp(client, echo, setRoute) + return appApp +} + +var ( + _wireDurationValue = time.Second * + 3 +)