Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[EPIC] sqlc 도입 #69

Merged
merged 12 commits into from
Apr 27, 2024
11 changes: 11 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,12 @@ run:
go run ./cmd/server

test:
make db:test:down
make db:test:up
go test ./... -count=1 -p=1
make db:test:down
test\:run:
go test ./... -count=1 -p=1

## Database ##
db\:up:
Expand Down Expand Up @@ -90,3 +93,11 @@ migrate\:down:
migrate -path db/migrations -database="${DATABASE_URL}" down
migrate\:create:
migrate create -ext sql -dir db/migrations -seq $(name)

## Queries (with sqlc) ##
sqlc\:install:
# sqlc
# https://docs.sqlc.dev/en/latest/
go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest
sqlc\:generate:
sqlc generate
27 changes: 14 additions & 13 deletions cmd/server/handler/user_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func NewUserHandler(userService service.UserService, authService service.AuthSer
// @Accept json
// @Produce json
// @Param request body user.RegisterUserRequest true "사용자 회원가입 요청"
// @Success 201 {object} user.RegisterUserView
// @Success 201 {object} user.InternalView
// @Router /users [post]
func (h *UserHandler) RegisterUser(c echo.Context) error {
var registerUserRequest user.RegisterUserRequest
Expand Down Expand Up @@ -76,22 +76,22 @@ func (h *UserHandler) CheckUserNickname(c echo.Context) error {
// @Accept json
// @Produce json
// @Param request body user.UserStatusRequest true "사용자 가입 상태 조회 요청"
// @Success 200 {object} user.UserStatusView
// @Success 200 {object} user.StatusView
// @Router /users/status [post]
func (h *UserHandler) FindUserStatusByEmail(c echo.Context) error {
var providerRequest user.UserStatusRequest
if err := pnd.ParseBody(c, &providerRequest); err != nil {
return c.JSON(err.StatusCode, err)
}

userStatus, err := h.userService.FindUserStatusByEmail(c.Request().Context(), providerRequest.Email)
if err != nil || userStatus == nil {
return c.JSON(http.StatusOK, user.UserStatusView{
Status: user.UserStatusNotRegistered,
userData, err := h.userService.FindUser(c.Request().Context(), user.FindUserParams{Email: &providerRequest.Email})
if err != nil {
return c.JSON(http.StatusOK, user.StatusView{
Status: user.StatusNotRegistered,
})
}

return c.JSON(http.StatusOK, userStatus.ToUserStatusView())
return c.JSON(http.StatusOK, user.NewStatusView(userData.FirebaseProviderType))
}

// FindUsers godoc
Expand All @@ -103,7 +103,7 @@ func (h *UserHandler) FindUserStatusByEmail(c echo.Context) error {
// @Param page query int false "페이지 번호" default(1)
// @Param size query int false "페이지 사이즈" default(10)
// @Param nickname query string false "닉네임 (완전 일치)"
// @Success 200 {object} user.UserWithoutPrivateInfoList
// @Success 200 {object} user.ListWithoutPrivateInfo
// @Router /users [get]
func (h *UserHandler) FindUsers(c echo.Context) error {
_, err := h.authService.VerifyAuthAndGetUser(c.Request().Context(), c.Request().Header.Get("Authorization"))
Expand All @@ -117,9 +117,10 @@ func (h *UserHandler) FindUsers(c echo.Context) error {
return c.JSON(err.StatusCode, err)
}

var res *user.UserWithoutPrivateInfoList
var res *user.ListWithoutPrivateInfo

res, err = h.userService.FindUsers(c.Request().Context(), page, size, nickname)
res, err = h.userService.FindUsers(c.Request().Context(),
user.FindUsersParams{Page: page, Size: size, Nickname: nickname})
if err != nil {
return c.JSON(err.StatusCode, err)
}
Expand Down Expand Up @@ -152,7 +153,7 @@ func (h *UserHandler) FindMyProfile(c echo.Context) error {
// @Produce json
// @Security FirebaseAuth
// @Param request body user.UpdateUserRequest true "사용자 프로필 수정 요청"
// @Success 200 {object} user.UpdateUserView
// @Success 200 {object} user.MyProfileView
// @Router /users/me [put]
func (h *UserHandler) UpdateMyProfile(c echo.Context) error {
foundUser, err := h.authService.VerifyAuthAndGetUser(c.Request().Context(), c.Request().Header.Get("Authorization"))
Expand All @@ -167,7 +168,7 @@ func (h *UserHandler) UpdateMyProfile(c echo.Context) error {
return c.JSON(err.StatusCode, err)
}

userModel, err := h.userService.UpdateUserByUID(
view, err := h.userService.UpdateUserByUID(
c.Request().Context(),
uid,
updateUserRequest.Nickname,
Expand All @@ -177,7 +178,7 @@ func (h *UserHandler) UpdateMyProfile(c echo.Context) error {
return c.JSON(err.StatusCode, err)
}

return c.JSON(http.StatusOK, userModel.ToUpdateUserView())
return c.JSON(http.StatusOK, view)
}

// DeleteMyAccount godoc
Expand Down
71 changes: 71 additions & 0 deletions internal/common/null.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package utils

import "database/sql"

func DerefOrEmpty[T any](val *T) T {
if val == nil {
var empty T
return empty
}
return *val
}

func IsNotNil[T any](val *T) bool {
return val != nil
}

func NullStrToStrPtr(val sql.NullString) *string {
if val.Valid {
return &val.String
}
return nil
}

func StrPtrToNullStr(val *string) sql.NullString {
return sql.NullString{
String: DerefOrEmpty(val),
Valid: IsNotNil(val),
}
}

func StrToNullStr(val string) sql.NullString {
return sql.NullString{
String: val,
Valid: val != "",
}
}

func NullInt64ToInt64Ptr(val sql.NullInt64) *int64 {
if val.Valid {
return &val.Int64
}
return nil
}

func Int64PtrToNullInt64(val *int64) sql.NullInt64 {
return sql.NullInt64{
Int64: DerefOrEmpty(val),
Valid: IsNotNil(val),
}
}

func IntPtrToNullInt64(val *int) sql.NullInt64 {
return sql.NullInt64{
Int64: int64(DerefOrEmpty(val)),
Valid: IsNotNil(val),
}
}

func IntToNullInt32(val int) sql.NullInt32 {
return sql.NullInt32{
Int32: int32(val),
Valid: val != 0,
}
}

func IntPtrToNullInt32(val *int) sql.NullInt32 {
return sql.NullInt32{
Int32: int32(DerefOrEmpty(val)),
Valid: IsNotNil(val),
}
}
22 changes: 22 additions & 0 deletions internal/common/pagination.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package utils

type PaginationClauses struct {
Offset int
Limit int
}

func OffsetAndLimit(page, size int) PaginationClauses {
if page < 1 {
page = 1
}

if size < 1 {
size = 10
}

offset := (page - 1) * size
return PaginationClauses{
Offset: offset,
Limit: size,
}
}
34 changes: 17 additions & 17 deletions internal/domain/sospost/view.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,25 +87,25 @@ func (p *SOSPost) ToWriteSOSPostView(
}

type FindSOSPostView struct {
ID int `json:"id"`
Author *user.UserWithoutPrivateInfo `json:"author"`
Title string `json:"title"`
Content string `json:"content"`
Media media.MediaViewList `json:"media"`
Conditions []ConditionView `json:"conditions"`
Pets []pet.PetView `json:"pets"`
Reward string `json:"reward"`
Dates []SOSDateView `json:"dates"`
CareType CareType `json:"careType"`
CarerGender CarerGender `json:"carerGender"`
RewardType RewardType `json:"rewardType"`
ThumbnailID int `json:"thumbnailId"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
ID int `json:"id"`
Author *user.WithoutPrivateInfo `json:"author"`
Title string `json:"title"`
Content string `json:"content"`
Media media.MediaViewList `json:"media"`
Conditions []ConditionView `json:"conditions"`
Pets []pet.PetView `json:"pets"`
Reward string `json:"reward"`
Dates []SOSDateView `json:"dates"`
CareType CareType `json:"careType"`
CarerGender CarerGender `json:"carerGender"`
RewardType RewardType `json:"rewardType"`
ThumbnailID int `json:"thumbnailId"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
}

func (p *SOSPost) ToFindSOSPostView(
author *user.UserWithoutPrivateInfo,
author *user.WithoutPrivateInfo,
mediaList media.MediaViewList,
conditions []ConditionView,
pets []pet.PetView,
Expand Down Expand Up @@ -151,7 +151,7 @@ func FromEmptySOSPostInfoList(sosPosts *SOSPostInfoList) *FindSOSPostListView {
}

func (p *SOSPostInfo) ToFindSOSPostInfoView(
author *user.UserWithoutPrivateInfo,
author *user.WithoutPrivateInfo,
mediaList media.MediaViewList,
conditions []ConditionView,
pets []pet.PetView,
Expand Down
77 changes: 77 additions & 0 deletions internal/domain/user/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package user

import (
"database/sql"
"time"

utils "github.com/pet-sitter/pets-next-door-api/internal/common"
databasegen "github.com/pet-sitter/pets-next-door-api/internal/infra/database/gen"
)

type FirebaseProviderType string

const (
FirebaseProviderTypeEmail FirebaseProviderType = "email"
FirebaseProviderTypeGoogle FirebaseProviderType = "google"
FirebaseProviderTypeApple FirebaseProviderType = "apple"
FirebaseProviderTypeKakao FirebaseProviderType = "kakao"
)

func (f FirebaseProviderType) String() string {
return string(f)
}

func (f FirebaseProviderType) NullString() sql.NullString {
return sql.NullString{String: string(f), Valid: true}
}

type WithProfileImage struct {
ID int
Email string
Password string
Nickname string
Fullname string
ProfileImageURL *string
FirebaseProviderType FirebaseProviderType
FirebaseUID string
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt sql.NullTime
}

func ToWithProfileImage(row databasegen.FindUserRow) *WithProfileImage {
return &WithProfileImage{
ID: int(row.ID),
Email: row.Email,
Nickname: row.Nickname,
Fullname: row.Fullname,
ProfileImageURL: utils.NullStrToStrPtr(row.ProfileImageUrl),
FirebaseProviderType: FirebaseProviderType(row.FbProviderType.String),
FirebaseUID: row.FbUid.String,
CreatedAt: row.CreatedAt,
UpdatedAt: row.UpdatedAt,
}
}

func (u *WithProfileImage) ToInternalView() *InternalView {
return &InternalView{
ID: u.ID,
Email: u.Email,
Nickname: u.Nickname,
Fullname: u.Fullname,
ProfileImageURL: u.ProfileImageURL,
FirebaseProviderType: u.FirebaseProviderType,
FirebaseUID: u.FirebaseUID,
}
}

func (u *WithProfileImage) ToMyProfileView() *MyProfileView {
return &MyProfileView{
ID: u.ID,
Email: u.Email,
Nickname: u.Nickname,
Fullname: u.Fullname,
ProfileImageURL: u.ProfileImageURL,
FirebaseProviderType: u.FirebaseProviderType,
}
}
39 changes: 39 additions & 0 deletions internal/domain/user/params.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package user

import (
utils "github.com/pet-sitter/pets-next-door-api/internal/common"
databasegen "github.com/pet-sitter/pets-next-door-api/internal/infra/database/gen"
)

type FindUserParams struct {
ID *int
Email *string
FbUID *string
IncludeDeleted bool
}

func (p *FindUserParams) ToDBParams() databasegen.FindUserParams {
return databasegen.FindUserParams{
ID: utils.IntPtrToNullInt32(p.ID),
Email: utils.StrPtrToNullStr(p.Email),
FbUid: utils.StrPtrToNullStr(p.FbUID),
IncludeDeleted: p.IncludeDeleted,
}
}

type FindUsersParams struct {
Page int
Size int
Nickname *string
IncludeDeleted bool
}

func (p *FindUsersParams) ToDBParams() databasegen.FindUsersParams {
pagination := utils.OffsetAndLimit(p.Page, p.Size)
return databasegen.FindUsersParams{
Limit: int32(pagination.Limit),
Offset: int32(pagination.Offset),
Nickname: utils.StrPtrToNullStr(p.Nickname),
IncludeDeleted: p.IncludeDeleted,
}
}
Loading