diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4150995..f60f335 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,6 +58,12 @@ jobs: - name: Check out code into the Go module directory uses: actions/checkout@v2 + # set up db + - name: SetUp db + run: | + docker-compose -f docker-compose.ci.yml up -d + sleep 15 + # Cache - name: Cache go module uses: actions/cache@v1 @@ -76,7 +82,13 @@ jobs: # Run test - name: Test - run: go test -v ./... + run: | + export MYSQL_USER=root + export MYSQL_PASSWORD=root + export MYSQL_HOST=localhost + export MYSQL_PORT=3306 + export MYSQL_DATABASE=wantum + go test -v ./... # slackの通知 slack-notification: diff --git a/Makefile b/Makefile index 09e2a33..38657b2 100644 --- a/Makefile +++ b/Makefile @@ -94,7 +94,7 @@ build: ## APIをビルドして立ち上げるコマンド ./binary/wantum dev-up: ## 全コンテナの起動 - docker-compose up -d + docker-compose -f docker-compose.yml up -d dev-stop: ## 全コンテナを止める docker-compose stop diff --git a/docker-compose.ci.yml b/docker-compose.ci.yml new file mode 100644 index 0000000..f4bdf26 --- /dev/null +++ b/docker-compose.ci.yml @@ -0,0 +1,17 @@ +version: '3.5' +services: + db: + image: mysql:5.7 + container_name: wantum_db_test + environment: + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: wantum + MYSQL_USER: worker + MYSQL_PASSWORD: password + TZ: 'Asia/Tokyo' + command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci + volumes: + - ./db/mysql/init.d:/docker-entrypoint-initdb.d + ports: + - 3306:3306 + restart: always \ No newline at end of file diff --git a/go.mod b/go.mod index e091e28..6948a39 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( cloud.google.com/go/firestore v1.2.0 // indirect firebase.google.com/go v3.12.0+incompatible github.com/go-sql-driver/mysql v1.5.0 - github.com/golang/mock v1.4.3 + github.com/golang/mock v1.4.4 github.com/golang/protobuf v1.4.1 github.com/google/uuid v1.1.2 github.com/google/wire v0.4.0 @@ -19,6 +19,7 @@ require ( github.com/rs/cors v1.7.0 github.com/stretchr/testify v1.5.1 go.uber.org/zap v1.10.0 + golang.org/x/arch v0.0.0-20200826200359-b19915210f00 // indirect golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect golang.org/x/tools v0.0.0-20200425043458-8463f397d07c // indirect golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 diff --git a/go.sum b/go.sum index 31b9b82..242680e 100644 --- a/go.sum +++ b/go.sum @@ -49,6 +49,7 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -73,14 +74,14 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3 h1:GV+pQPG/EUUbkh47niozDcADz6go/dUwhVzdUQHIVRw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -94,7 +95,6 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -165,6 +165,7 @@ go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/arch v0.0.0-20200826200359-b19915210f00/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -218,7 +219,6 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200421231249-e086a090c8fd h1:QPwSajcTUrFriMF1nJ3XzgoqakqQEsnZf9LdXdi2nkI= golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -365,7 +365,6 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= @@ -394,5 +393,6 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/pkg/api/usecase/wishcard/interactor.go b/pkg/api/usecase/wishcard/interactor.go new file mode 100644 index 0000000..ed48bba --- /dev/null +++ b/pkg/api/usecase/wishcard/interactor.go @@ -0,0 +1,612 @@ +package wishcard + +import ( + "context" + "errors" + "fmt" + "net/http" + "time" + + tagEntity "wantum/pkg/domain/entity/tag" + wishCardEntity "wantum/pkg/domain/entity/wishcard" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/service/place" + "wantum/pkg/domain/service/profile" + "wantum/pkg/domain/service/tag" + "wantum/pkg/domain/service/user" + "wantum/pkg/domain/service/wishcard" + "wantum/pkg/tlog" + "wantum/pkg/werrors" + + "google.golang.org/grpc/codes" +) + +type Interactor interface { + CreateNewWishCard(ctx context.Context, userID, categoryID int, activity, description, place string, date *time.Time, tags []string) (*wishCardEntity.Entity, error) + UpdateActivity(ctx context.Context, userID, wishCardID int, activity string) (*wishCardEntity.Entity, error) + UpdateDescription(ctx context.Context, userID, wishCardID int, description string) (*wishCardEntity.Entity, error) + UpdatePlace(ctx context.Context, userID, wishCardID int, place string) (*wishCardEntity.Entity, error) + UpdateDate(ctx context.Context, userID, wishCardID int, date *time.Time) (*wishCardEntity.Entity, error) + UpdateWishCardWithCategoryID(ctx context.Context, wishCardID, userID int, activity, description, place string, date, doneAt *time.Time, categoryID int, tags []string) (*wishCardEntity.Entity, error) + DeleteWishCardByID(ctx context.Context, wishCardID int) error + GetByID(ctx context.Context, wishCardID int) (*wishCardEntity.Entity, error) + GetByCategoryID(ctx context.Context, categoryID int) (wishCardEntity.EntitySlice, error) + AddTags(ctx context.Context, userID, wishCardID int, tags []string) (*wishCardEntity.Entity, error) + DeleteTags(ctx context.Context, userID, wishCardID int, tagIDs []int) (*wishCardEntity.Entity, error) +} + +type interactor struct { + masterTxManager repository.MasterTxManager + wishCardService wishcard.Service + userService user.Service + profileService profile.Service + tagService tag.Service + placeService place.Service +} + +func New(masterTxManager repository.MasterTxManager, wishCardService wishcard.Service, userService user.Service, profileService profile.Service, tagService tag.Service, placeService place.Service) Interactor { + return &interactor{ + masterTxManager: masterTxManager, + wishCardService: wishCardService, + userService: userService, + profileService: profileService, + tagService: tagService, + placeService: placeService, + } +} + +// TODO: 先に取得した値ボンボン詰め込んで大丈夫か...? +// TODO: upd系の編集権限があるか + +func (i *interactor) CreateNewWishCard(ctx context.Context, userID, categoryID int, activity, description, place string, date *time.Time, tags []string) (*wishCardEntity.Entity, error) { + // validation + var err error + if err = validateActivity(activity); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + if err = validateDescription(description); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + if err = validatePlace(place); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + if err = validateDate(date); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + if err = validateTags(tags); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + + // create new entity + var newWishCard *wishCardEntity.Entity + err = i.masterTxManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + _author, err := i.userService.GetByPK(ctx, masterTx, userID) + if err != nil { + return werrors.Stack(err) + } + if _author == nil { + return werrors.Stack(werrors.UserNotFound) + } + _profile, err := i.profileService.GetByUserID(ctx, masterTx, _author.ID) + if err != nil { + return werrors.Stack(err) + } + + _place, err := i.placeService.Create(ctx, masterTx, place) + if err != nil { + // TODO: placeがすでにあったら無限に増えてしまう + return werrors.Stack(err) + } + + // TODO: きたない + tagIDs := make([]int, 0, len(tags)) + _tags := make(tagEntity.EntitySlice, 0, len(tags)) + for _, tagName := range tags { + var tag *tagEntity.Entity + tag, err = i.tagService.GetByName(ctx, masterTx, tagName) + if err != nil { + return werrors.Stack(err) + } + if tag == nil { + tag, err = i.tagService.Create(ctx, masterTx, tagName) + if err != nil { + return werrors.Stack(err) + } + } + _tags = append(_tags, tag) + tagIDs = append(tagIDs, tag.ID) + } + + // TODO: カテゴリが存在するか確認する + + newWishCard, err = i.wishCardService.Create(ctx, masterTx, activity, description, date, _author.ID, categoryID, _place.ID, tagIDs) + if err != nil { + return werrors.Stack(err) + } + newWishCard.Author = _author + newWishCard.Author.Profile = _profile + newWishCard.Place = _place + newWishCard.Tags = _tags + + return nil + }) + if err != nil { + return nil, werrors.Stack(err) + } + return newWishCard, nil +} + +func (i *interactor) UpdateWishCardWithCategoryID(ctx context.Context, wishCardID, userID int, activity, description, place string, date, doneAt *time.Time, categoryID int, tags []string) (*wishCardEntity.Entity, error) { + var err error + if err = validateActivity(activity); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + if err = validateDescription(description); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + if err = validatePlace(place); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + if err = validateDate(date); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + if err = validateTags(tags); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + + var wishCard *wishCardEntity.Entity + err = i.masterTxManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + _author, err := i.userService.GetByPK(ctx, masterTx, userID) + if err != nil { + return werrors.Stack(err) + } + if _author == nil { + return werrors.Stack(werrors.UserNotFound) + } + _profile, err := i.profileService.GetByUserID(ctx, masterTx, _author.ID) + if err != nil { + return werrors.Stack(err) + } + + _place, err := i.placeService.Create(ctx, masterTx, place) + if err != nil { + // TODO: placeがすでにあったら無限に増えてしまう + return werrors.Stack(err) + } + + tagIDs := make([]int, 0, len(tags)) + _tags := make(tagEntity.EntitySlice, 0, len(tags)) + for _, tagName := range tags { + var tag *tagEntity.Entity + tag, err = i.tagService.GetByName(ctx, masterTx, tagName) + if err != nil { + return werrors.Stack(err) + } + if tag == nil { + tag, err = i.tagService.Create(ctx, masterTx, tagName) + if err != nil { + return werrors.Stack(err) + } + } + _tags = append(_tags, tag) + tagIDs = append(tagIDs, tag.ID) + } + + wishCard, err = i.wishCardService.UpdateWithCategoryID(ctx, masterTx, wishCardID, activity, description, date, doneAt, userID, categoryID, _place.ID, tagIDs) + if err != nil { + return werrors.Stack(err) + } + wishCard.Author = _author + wishCard.Author.Profile = _profile + wishCard.Place = _place + wishCard.Tags = _tags + return nil + }) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (i *interactor) DeleteWishCardByID(ctx context.Context, wishCardID int) error { + var err error + err = i.masterTxManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = i.wishCardService.Delete(ctx, masterTx, wishCardID); err != nil { + return werrors.Stack(err) + } + + return nil + }) + if err != nil { + return werrors.Stack(err) + } + return nil +} + +func (i *interactor) GetByID(ctx context.Context, wishCardID int) (*wishCardEntity.Entity, error) { + var wishCard *wishCardEntity.Entity + var err error + err = i.masterTxManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + wishCard, err = i.wishCardService.GetByID(ctx, masterTx, wishCardID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Author, err = i.userService.GetByPK(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + // QUESTION: author == nilだった時? + wishCard.Author.Profile, err = i.profileService.GetByUserID(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Place, err = i.placeService.GetByID(ctx, masterTx, wishCard.Place.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Tags, err = i.tagService.GetByWishCardID(ctx, masterTx, wishCard.ID) + if err != nil { + return werrors.Stack(err) + } + return nil + }) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (i *interactor) GetByCategoryID(ctx context.Context, categoryID int) (wishCardEntity.EntitySlice, error) { + var wishCards wishCardEntity.EntitySlice + var err error + err = i.masterTxManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + wishCards, err = i.wishCardService.GetByCategoryID(ctx, masterTx, categoryID) + if err != nil { + return werrors.Stack(err) + } + // OPTIMIZE: でら遅い...? + for _, wishCard := range wishCards { + wishCard.Author, err = i.userService.GetByPK(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + // QUESTION: author == nilだった時? + wishCard.Author.Profile, err = i.profileService.GetByUserID(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Place, err = i.placeService.GetByID(ctx, masterTx, wishCard.Place.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Tags, err = i.tagService.GetByWishCardID(ctx, masterTx, wishCard.ID) + if err != nil { + return werrors.Stack(err) + } + } + return nil + }) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCards, nil +} + +func (i *interactor) UpdateActivity(ctx context.Context, userID, wishCardID int, activity string) (*wishCardEntity.Entity, error) { + var err error + if err = validateActivity(activity); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + + var wishCard = new(wishCardEntity.Entity) + err = i.masterTxManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + wishCard, err = i.wishCardService.UpdateActivity(ctx, masterTx, wishCardID, activity) + if err != nil { + return werrors.Stack(err) + } + wishCard.Author, err = i.userService.GetByPK(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + // QUESTION: author == nilだった時? + wishCard.Author.Profile, err = i.profileService.GetByUserID(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Place, err = i.placeService.GetByID(ctx, masterTx, wishCard.Place.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Tags, err = i.tagService.GetByWishCardID(ctx, masterTx, wishCard.ID) + if err != nil { + return werrors.Stack(err) + } + return nil + }) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil + +} + +func (i *interactor) UpdateDescription(ctx context.Context, userID, wishCardID int, description string) (*wishCardEntity.Entity, error) { + var err error + if err = validateDescription(description); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + + var wishCard = new(wishCardEntity.Entity) + err = i.masterTxManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + wishCard, err = i.wishCardService.UpdateDescription(ctx, masterTx, wishCardID, description) + if err != nil { + return werrors.Stack(err) + } + wishCard.Author, err = i.userService.GetByPK(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + // QUESTION: author == nilだった時? + wishCard.Author.Profile, err = i.profileService.GetByUserID(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Place, err = i.placeService.GetByID(ctx, masterTx, wishCard.Place.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Tags, err = i.tagService.GetByWishCardID(ctx, masterTx, wishCard.ID) + if err != nil { + return werrors.Stack(err) + } + return nil + }) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (i *interactor) UpdatePlace(ctx context.Context, userID, wishCardID int, place string) (*wishCardEntity.Entity, error) { + var err error + if err = validatePlace(place); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + + var wishCard = new(wishCardEntity.Entity) + err = i.masterTxManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + wishCard.Place, err = i.placeService.Create(ctx, masterTx, place) + if err != nil { + // TODO: placeがすでにあったら無限に増えてしまう + return werrors.Stack(err) + } + wishCard, err = i.wishCardService.UpdatePlace(ctx, masterTx, wishCardID, wishCard.Place.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Author, err = i.userService.GetByPK(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + // QUESTION: author == nilだった時? + wishCard.Author.Profile, err = i.profileService.GetByUserID(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Tags, err = i.tagService.GetByWishCardID(ctx, masterTx, wishCard.ID) + if err != nil { + return werrors.Stack(err) + } + return nil + }) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (i *interactor) UpdateDate(ctx context.Context, userID, wishCardID int, date *time.Time) (*wishCardEntity.Entity, error) { + var err error + if err = validateDate(date); err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.Stack(err) + } + + var wishCard = new(wishCardEntity.Entity) + err = i.masterTxManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + wishCard, err = i.wishCardService.UpdateDate(ctx, masterTx, wishCardID, date) + if err != nil { + return werrors.Stack(err) + } + wishCard.Author, err = i.userService.GetByPK(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + // QUESTION: author == nilだった時? + wishCard.Author.Profile, err = i.profileService.GetByUserID(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Place, err = i.placeService.GetByID(ctx, masterTx, wishCard.Place.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Tags, err = i.tagService.GetByWishCardID(ctx, masterTx, wishCard.ID) + if err != nil { + return werrors.Stack(err) + } + return nil + }) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (i *interactor) AddTags(ctx context.Context, userID, wishCardID int, tags []string) (*wishCardEntity.Entity, error) { + var wishCard = new(wishCardEntity.Entity) + var err error + err = i.masterTxManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + // create or get tagIDs + tagIDs := make([]int, 0, len(tags)) + for _, tagName := range tags { + var tag *tagEntity.Entity + tag, err = i.tagService.GetByName(ctx, masterTx, tagName) + if err != nil { + return werrors.Stack(err) + } + if tag == nil { + tag, err = i.tagService.Create(ctx, masterTx, tagName) + if err != nil { + return werrors.Stack(err) + } + } + tagIDs = append(tagIDs, tag.ID) + } + // add relation + wishCard, err = i.wishCardService.AddTags(ctx, masterTx, wishCardID, tagIDs) + if err != nil { + return werrors.Stack(err) + } + wishCard.Author, err = i.userService.GetByPK(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + // QUESTION: author == nilだった時? + wishCard.Author.Profile, err = i.profileService.GetByUserID(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Place, err = i.placeService.GetByID(ctx, masterTx, wishCard.Place.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Tags, err = i.tagService.GetByWishCardID(ctx, masterTx, wishCard.ID) + if err != nil { + return werrors.Stack(err) + } + return nil + }) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (i *interactor) DeleteTags(ctx context.Context, userID, wishCardID int, tagIDs []int) (*wishCardEntity.Entity, error) { + var wishCard = new(wishCardEntity.Entity) + var err error + err = i.masterTxManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + // delete relation + wishCard, err = i.wishCardService.DeleteTags(ctx, masterTx, wishCardID, tagIDs) + if err != nil { + return werrors.Stack(err) + } + wishCard.Author, err = i.userService.GetByPK(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + // QUESTION: author == nilだった時? + wishCard.Author.Profile, err = i.profileService.GetByUserID(ctx, masterTx, wishCard.Author.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Place, err = i.placeService.GetByID(ctx, masterTx, wishCard.Place.ID) + if err != nil { + return werrors.Stack(err) + } + wishCard.Tags, err = i.tagService.GetByWishCardID(ctx, masterTx, wishCard.ID) + if err != nil { + return werrors.Stack(err) + } + return nil + }) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func validateActivity(activity string) error { + if activity == "" { + err := errors.New("activity is empty error") + return werrors.Newf(err, codes.InvalidArgument, http.StatusBadRequest, "「やりたいこと」は必須項目です。", "activity is required.") + } + if len(activity) > 50 { + err := errors.New("activity is too long error") + return werrors.Newf(err, codes.InvalidArgument, http.StatusBadRequest, "「やりたいこと」が長すぎます。", "activity is too long.") + } + return nil +} + +func validateDescription(description string) error { + if len(description) > 100 { + err := errors.New("description is too long error") + return werrors.Newf(err, codes.InvalidArgument, http.StatusBadRequest, "「詳細」が長すぎます。", "description is too long.") + } + return nil +} + +func validatePlace(place string) error { + if place == "" { + err := errors.New("place is empty error") + return werrors.Newf(err, codes.InvalidArgument, http.StatusBadRequest, "「場所」は必須項目です。", "place is required.") + } + if len(place) > 200 { + err := errors.New("place is too long error") + return werrors.Newf(err, codes.InvalidArgument, http.StatusBadRequest, "「場所」が長すぎます。", "place is too long.") + } + return nil +} + +func validateDate(date *time.Time) error { + if date == nil { + err := errors.New("date is empty error") + return werrors.Newf(err, codes.InvalidArgument, http.StatusBadRequest, "「日付」は必須項目です。", "date is required.") + } + if date.Before(time.Now()) { + err := errors.New("date is in the past") + return werrors.Newf(err, codes.InvalidArgument, http.StatusBadRequest, "過去の「日付」は指定できません。", "date is in the past.") + } + return nil +} + +func validateTags(tags []string) error { + for _, tag := range tags { + if err := validateTag(tag); err != nil { + return err + } + } + return nil +} + +func validateTag(tag string) error { + if tag == "" { + err := errors.New("tag is invalid error") + return werrors.Newf( + err, + codes.InvalidArgument, + http.StatusBadRequest, + fmt.Sprintf("「%s」は無効なタグです。", tag), + fmt.Sprintf("「%s」is invalid.", tag), + ) + } + if len(tag) > 100 { + err := errors.New("tag is too long error") + return werrors.Newf(err, codes.InvalidArgument, http.StatusBadRequest, "「タグ」が長すぎます。", "tag is too long.") + } + return nil +} diff --git a/pkg/api/usecase/wishcard/interactor_test.go b/pkg/api/usecase/wishcard/interactor_test.go new file mode 100644 index 0000000..c1197a5 --- /dev/null +++ b/pkg/api/usecase/wishcard/interactor_test.go @@ -0,0 +1,765 @@ +package wishcard + +import ( + "context" + "os" + "strings" + "testing" + "time" + + placeEntity "wantum/pkg/domain/entity/place" + tagEntity "wantum/pkg/domain/entity/tag" + userEntity "wantum/pkg/domain/entity/user" + profileEntity "wantum/pkg/domain/entity/userprofile" + wishCardEntity "wantum/pkg/domain/entity/wishcard" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/service/place/mock_place" + "wantum/pkg/domain/service/profile/mock_profile" + "wantum/pkg/domain/service/tag/mock_tag" + "wantum/pkg/domain/service/user/mock_user" + "wantum/pkg/domain/service/wishcard/mock_wish_card" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +var ( + masterTx repository.MasterTx + masterTxManager repository.MasterTxManager + + dummyDate = time.Date(2040, 9, 1, 12, 0, 0, 0, time.Local) + dummyActivity = "dummyActivity" + dummyDescription = "dummyDescription" + dummyTagName1 = "dummyTag1" + dummyTagName2 = "dummyTag2" + dummyPlaceName = "dummyPlace" + + dummyProfile = &profileEntity.Entity{ + UserID: 1, + Name: "dummyName", + Thumbnail: "dummyThumbnail", + Bio: "dummyBio", + Gender: 1, + Phone: "12345678901", + Birth: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: &dummyDate, + } + + dummyUser = &userEntity.Entity{ + ID: 1, + AuthID: "dummyID", + UserName: "dummyUserName", + Mail: "hogehoge@example.com", + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: &dummyDate, + } + + dummyTag1 = &tagEntity.Entity{ + ID: 1, + Name: dummyTagName1, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: &dummyDate, + } + + dummyTag2 = &tagEntity.Entity{ + ID: 2, + Name: dummyTagName2, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: nil, + } + + dummyTagSlice = tagEntity.EntitySlice{ + dummyTag1, + dummyTag2, + } + + dummyPlace = &placeEntity.Entity{ + ID: 1, + Name: dummyPlaceName, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: nil, + } +) + +func TestMain(m *testing.M) { + before() + code := m.Run() + after() + os.Exit(code) +} + +func before() { + masterTx = repository.NewMockMasterTx() + masterTxManager = repository.NewMockMasterTxManager(masterTx) +} + +func after() {} + +func TestInteractor_CreateNewWishCard(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyWishCard := &wishCardEntity.Entity{ + ID: 1, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: nil, + } + + userService := mock_user.NewMockService(ctrl) + userService.EXPECT().GetByPK(ctx, masterTx, gomock.Any()).Return(dummyUser, nil) + + profileService := mock_profile.NewMockService(ctrl) + profileService.EXPECT().GetByUserID(ctx, masterTx, gomock.Any()).Return(dummyProfile, nil) + + placeService := mock_place.NewMockService(ctrl) + placeService.EXPECT().Create(ctx, masterTx, gomock.Any()).Return(dummyPlace, nil) + + wishCardService := mock_wish_card.NewMockService(ctrl) + wishCardService.EXPECT().Create(ctx, masterTx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(dummyWishCard, nil) + + tagService := mock_tag.NewMockService(ctrl) + tagService.EXPECT().GetByName(ctx, masterTx, dummyTagName1).Return(dummyTag1, nil) + tagService.EXPECT().GetByName(ctx, masterTx, dummyTagName2).Return(nil, nil) + tagService.EXPECT().Create(ctx, masterTx, dummyTagName2).Return(dummyTag2, nil) + + interactor := New(masterTxManager, wishCardService, userService, profileService, tagService, placeService) + + tags := []string{dummyTagName1, dummyTagName2} + result, err := interactor.CreateNewWishCard(ctx, 1, 1, dummyActivity, dummyDescription, dummyPlaceName, &dummyDate, tags) + + assert.NoError(t, err) + assert.NotNil(t, result) + + // validate time + assert.Equal(t, (*time.Time)(nil), result.DeletedAt) + assert.Equal(t, (*time.Time)(nil), result.DoneAt) + // validate place + assert.Equal(t, dummyPlaceName, result.Place.Name) + // validate tag + assert.Equal(t, 2, len(result.Tags)) + assert.Equal(t, dummyTagName1, result.Tags[0].Name) + }) +} + +func TestInteractor_UpdateWishCardWithCategoryID(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyWishCard := &wishCardEntity.Entity{ + ID: 1, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: nil, + } + + userService := mock_user.NewMockService(ctrl) + userService.EXPECT().GetByPK(ctx, masterTx, gomock.Any()).Return(dummyUser, nil) + + profileService := mock_profile.NewMockService(ctrl) + profileService.EXPECT().GetByUserID(ctx, masterTx, gomock.Any()).Return(dummyProfile, nil) + + placeService := mock_place.NewMockService(ctrl) + placeService.EXPECT().Create(ctx, masterTx, gomock.Any()).Return(dummyPlace, nil) + + wishCardService := mock_wish_card.NewMockService(ctrl) + wishCardService.EXPECT().UpdateWithCategoryID(ctx, masterTx, gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(dummyWishCard, nil) + + tagService := mock_tag.NewMockService(ctrl) + tagService.EXPECT().GetByName(ctx, masterTx, dummyTagName1).Return(dummyTag1, nil) + tagService.EXPECT().GetByName(ctx, masterTx, dummyTagName2).Return(nil, nil) + tagService.EXPECT().Create(ctx, masterTx, dummyTagName2).Return(dummyTag2, nil) + + interactor := New(masterTxManager, wishCardService, userService, profileService, tagService, placeService) + + tags := []string{dummyTagName1, dummyTagName2} + result, err := interactor.UpdateWishCardWithCategoryID(ctx, 1, 1, dummyActivity, dummyDescription, dummyPlaceName, &dummyDate, &dummyDate, 1, tags) + + assert.NoError(t, err) + assert.NotNil(t, result) + + // validate time + assert.Equal(t, (*time.Time)(nil), result.DeletedAt) + assert.NotEqual(t, (*time.Time)(nil), result.DoneAt) + // validate place + assert.Equal(t, dummyPlaceName, result.Place.Name) + // validate tag + assert.Equal(t, 2, len(result.Tags)) + assert.Equal(t, dummyTagName1, result.Tags[0].Name) + }) +} + +func TestInteractor_DeleteWishCard(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + userService := mock_user.NewMockService(ctrl) + + profileService := mock_profile.NewMockService(ctrl) + + placeService := mock_place.NewMockService(ctrl) + + wishCardService := mock_wish_card.NewMockService(ctrl) + wishCardService.EXPECT().Delete(ctx, masterTx, 1).Return(nil) + + tagService := mock_tag.NewMockService(ctrl) + + interactor := New(masterTxManager, wishCardService, userService, profileService, tagService, placeService) + + err := interactor.DeleteWishCardByID(ctx, 1) + + assert.NoError(t, err) + }) +} + +func TestInteractor_GetByID(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + dummyWishCard := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: nil, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + userService := mock_user.NewMockService(ctrl) + userService.EXPECT().GetByPK(ctx, masterTx, gomock.Any()).Return(dummyUser, nil) + + profileService := mock_profile.NewMockService(ctrl) + profileService.EXPECT().GetByUserID(ctx, masterTx, gomock.Any()).Return(dummyProfile, nil) + + placeService := mock_place.NewMockService(ctrl) + placeService.EXPECT().GetByID(ctx, masterTx, gomock.Any()).Return(dummyPlace, nil) + + wishCardService := mock_wish_card.NewMockService(ctrl) + wishCardService.EXPECT().GetByID(ctx, masterTx, gomock.Any()).Return(dummyWishCard, nil) + + tagService := mock_tag.NewMockService(ctrl) + tagService.EXPECT().GetByWishCardID(ctx, masterTx, gomock.Any()).Return(dummyTagSlice, nil) + + interactor := New(masterTxManager, wishCardService, userService, profileService, tagService, placeService) + + result, err := interactor.GetByID(ctx, 1) + + assert.NoError(t, err) + assert.NotNil(t, result) + + // validate place + assert.Equal(t, dummyPlaceName, result.Place.Name) + // validate tag + assert.Equal(t, 2, len(result.Tags)) + assert.Equal(t, dummyTagName1, result.Tags[0].Name) + }) +} + +func TestInteractor_GetByCategoryID(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyWishCards := wishCardEntity.EntitySlice{ + &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: nil, + Place: &placeEntity.Entity{ + ID: 1, + }, + }, + &wishCardEntity.Entity{ + ID: 2, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: nil, + Place: &placeEntity.Entity{ + ID: 1, + }, + }, + } + + userService := mock_user.NewMockService(ctrl) + userService.EXPECT().GetByPK(ctx, masterTx, gomock.Any()).Return(dummyUser, nil).Times(2) + + profileService := mock_profile.NewMockService(ctrl) + profileService.EXPECT().GetByUserID(ctx, masterTx, gomock.Any()).Return(dummyProfile, nil).Times(2) + + placeService := mock_place.NewMockService(ctrl) + placeService.EXPECT().GetByID(ctx, masterTx, gomock.Any()).Return(dummyPlace, nil).Times(2) + + wishCardService := mock_wish_card.NewMockService(ctrl) + wishCardService.EXPECT().GetByCategoryID(ctx, masterTx, gomock.Any()).Return(dummyWishCards, nil) + + tagService := mock_tag.NewMockService(ctrl) + tagService.EXPECT().GetByWishCardID(ctx, masterTx, gomock.Any()).Return(dummyTagSlice, nil).Times(2) + + interactor := New(masterTxManager, wishCardService, userService, profileService, tagService, placeService) + + wishCards, err := interactor.GetByCategoryID(ctx, 1) + + assert.NoError(t, err) + assert.NotNil(t, wishCards) + assert.Equal(t, 2, len(wishCards)) + + assert.Equal(t, dummyPlaceName, wishCards[0].Place.Name) + assert.Equal(t, dummyPlaceName, wishCards[1].Place.Name) + + assert.Equal(t, dummyTagName1, wishCards[0].Tags[0].Name) + assert.Equal(t, 2, len(wishCards[0].Tags)) + assert.Equal(t, dummyTagName1, wishCards[1].Tags[0].Name) + assert.Equal(t, 2, len(wishCards[1].Tags)) + }) +} + +func TestInteractor_UpdateActivity(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyWishCard := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: nil, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + userService := mock_user.NewMockService(ctrl) + userService.EXPECT().GetByPK(ctx, masterTx, gomock.Any()).Return(dummyUser, nil) + + profileService := mock_profile.NewMockService(ctrl) + profileService.EXPECT().GetByUserID(ctx, masterTx, gomock.Any()).Return(dummyProfile, nil) + + placeService := mock_place.NewMockService(ctrl) + placeService.EXPECT().GetByID(ctx, masterTx, gomock.Any()).Return(dummyPlace, nil) + + wishCardService := mock_wish_card.NewMockService(ctrl) + wishCardService.EXPECT().UpdateActivity(ctx, masterTx, gomock.Any(), gomock.Any()).Return(dummyWishCard, nil) + + tagService := mock_tag.NewMockService(ctrl) + tagService.EXPECT().GetByWishCardID(ctx, masterTx, gomock.Any()).Return(dummyTagSlice, nil) + + interactor := New(masterTxManager, wishCardService, userService, profileService, tagService, placeService) + + result, err := interactor.UpdateActivity(ctx, 1, 1, dummyActivity) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) +} + +func TestInteractor_UpdateDescription(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyWishCard := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: nil, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + userService := mock_user.NewMockService(ctrl) + userService.EXPECT().GetByPK(ctx, masterTx, gomock.Any()).Return(dummyUser, nil) + + profileService := mock_profile.NewMockService(ctrl) + profileService.EXPECT().GetByUserID(ctx, masterTx, gomock.Any()).Return(dummyProfile, nil) + + placeService := mock_place.NewMockService(ctrl) + placeService.EXPECT().GetByID(ctx, masterTx, gomock.Any()).Return(dummyPlace, nil) + + wishCardService := mock_wish_card.NewMockService(ctrl) + wishCardService.EXPECT().UpdateDescription(ctx, masterTx, gomock.Any(), gomock.Any()).Return(dummyWishCard, nil) + + tagService := mock_tag.NewMockService(ctrl) + tagService.EXPECT().GetByWishCardID(ctx, masterTx, gomock.Any()).Return(dummyTagSlice, nil) + + interactor := New(masterTxManager, wishCardService, userService, profileService, tagService, placeService) + + result, err := interactor.UpdateDescription(ctx, 1, 1, dummyDescription) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) +} + +func TestInteractor_UpdatePlace(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyWishCard := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: nil, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + userService := mock_user.NewMockService(ctrl) + userService.EXPECT().GetByPK(ctx, masterTx, gomock.Any()).Return(dummyUser, nil) + + profileService := mock_profile.NewMockService(ctrl) + profileService.EXPECT().GetByUserID(ctx, masterTx, gomock.Any()).Return(dummyProfile, nil) + + placeService := mock_place.NewMockService(ctrl) + placeService.EXPECT().Create(ctx, masterTx, gomock.Any()).Return(dummyPlace, nil) + + wishCardService := mock_wish_card.NewMockService(ctrl) + wishCardService.EXPECT().UpdatePlace(ctx, masterTx, gomock.Any(), gomock.Any()).Return(dummyWishCard, nil) + + tagService := mock_tag.NewMockService(ctrl) + tagService.EXPECT().GetByWishCardID(ctx, masterTx, gomock.Any()).Return(dummyTagSlice, nil) + + interactor := New(masterTxManager, wishCardService, userService, profileService, tagService, placeService) + + result, err := interactor.UpdatePlace(ctx, 1, 1, dummyPlaceName) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) +} + +func TestInteractor_UpdateDate(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyWishCard := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: nil, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + userService := mock_user.NewMockService(ctrl) + userService.EXPECT().GetByPK(ctx, masterTx, gomock.Any()).Return(dummyUser, nil) + + profileService := mock_profile.NewMockService(ctrl) + profileService.EXPECT().GetByUserID(ctx, masterTx, gomock.Any()).Return(dummyProfile, nil) + + placeService := mock_place.NewMockService(ctrl) + placeService.EXPECT().GetByID(ctx, masterTx, gomock.Any()).Return(dummyPlace, nil) + + wishCardService := mock_wish_card.NewMockService(ctrl) + wishCardService.EXPECT().UpdateDate(ctx, masterTx, gomock.Any(), gomock.Any()).Return(dummyWishCard, nil) + + tagService := mock_tag.NewMockService(ctrl) + tagService.EXPECT().GetByWishCardID(ctx, masterTx, gomock.Any()).Return(dummyTagSlice, nil) + + interactor := New(masterTxManager, wishCardService, userService, profileService, tagService, placeService) + + result, err := interactor.UpdateDate(ctx, 1, 1, &dummyDate) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) +} + +func TestInteractor_AddTags(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyWishCard := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: nil, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + userService := mock_user.NewMockService(ctrl) + userService.EXPECT().GetByPK(ctx, masterTx, gomock.Any()).Return(dummyUser, nil) + + profileService := mock_profile.NewMockService(ctrl) + profileService.EXPECT().GetByUserID(ctx, masterTx, gomock.Any()).Return(dummyProfile, nil) + + placeService := mock_place.NewMockService(ctrl) + placeService.EXPECT().GetByID(ctx, masterTx, gomock.Any()).Return(dummyPlace, nil) + + wishCardService := mock_wish_card.NewMockService(ctrl) + wishCardService.EXPECT().AddTags(ctx, masterTx, gomock.Any(), gomock.Any()).Return(dummyWishCard, nil) + + tagService := mock_tag.NewMockService(ctrl) + tagService.EXPECT().GetByName(ctx, masterTx, dummyTagName1).Return(dummyTag1, nil) + tagService.EXPECT().GetByName(ctx, masterTx, dummyTagName2).Return(nil, nil) + tagService.EXPECT().Create(ctx, masterTx, dummyTagName2).Return(dummyTag2, nil) + tagService.EXPECT().GetByWishCardID(ctx, masterTx, gomock.Any()).Return(dummyTagSlice, nil) + + interactor := New(masterTxManager, wishCardService, userService, profileService, tagService, placeService) + + result, err := interactor.AddTags(ctx, 1, 1, []string{dummyTagName1, dummyTagName2}) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) +} + +func TestInteractor_DeleteTags(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyWishCard := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: nil, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + userService := mock_user.NewMockService(ctrl) + userService.EXPECT().GetByPK(ctx, masterTx, gomock.Any()).Return(dummyUser, nil) + + profileService := mock_profile.NewMockService(ctrl) + profileService.EXPECT().GetByUserID(ctx, masterTx, gomock.Any()).Return(dummyProfile, nil) + + placeService := mock_place.NewMockService(ctrl) + placeService.EXPECT().GetByID(ctx, masterTx, gomock.Any()).Return(dummyPlace, nil) + + wishCardService := mock_wish_card.NewMockService(ctrl) + wishCardService.EXPECT().DeleteTags(ctx, masterTx, gomock.Any(), gomock.Any()).Return(dummyWishCard, nil) + + tagService := mock_tag.NewMockService(ctrl) + tagService.EXPECT().GetByWishCardID(ctx, masterTx, gomock.Any()).Return(dummyTagSlice, nil) + + interactor := New(masterTxManager, wishCardService, userService, profileService, tagService, placeService) + + result, err := interactor.DeleteTags(ctx, 1, 1, []int{1, 2}) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) +} + +// validation test +func TestIntereractor_validateActivity(t *testing.T) { + t.Run("success", func(t *testing.T) { + err := validateActivity("activityyyy") + assert.NoError(t, err) + }) + + t.Run("success_文字列制限ぴったり", func(t *testing.T) { + err := validateActivity(strings.Repeat("a", 50)) + assert.NoError(t, err) + }) + + t.Run("failure_空値", func(t *testing.T) { + err := validateActivity("") + assert.Error(t, err) + }) + + t.Run("failure_文字列超過", func(t *testing.T) { + err := validateActivity(strings.Repeat("a", 51)) + assert.Error(t, err) + }) +} + +func TestIntereractor_validateDescription(t *testing.T) { + t.Run("success", func(t *testing.T) { + err := validateDescription("sampleDescription") + assert.NoError(t, err) + }) + + t.Run("success_文字列制限ぴったり", func(t *testing.T) { + err := validateDescription(strings.Repeat("a", 100)) + assert.NoError(t, err) + }) + + t.Run("success_空値", func(t *testing.T) { + err := validateDescription("") + assert.NoError(t, err) + }) + + t.Run("failure_文字列超過", func(t *testing.T) { + err := validateDescription(strings.Repeat("a", 101)) + assert.Error(t, err) + }) +} + +func TestIntereractor_validatePlace(t *testing.T) { + t.Run("success", func(t *testing.T) { + err := validatePlace("samplePlace") + assert.NoError(t, err) + }) + + t.Run("success_文字列制限ぴったり", func(t *testing.T) { + err := validatePlace(strings.Repeat("a", 200)) + assert.NoError(t, err) + }) + + t.Run("failure_空値", func(t *testing.T) { + err := validatePlace("") + assert.Error(t, err) + }) + + t.Run("failure_文字列超過", func(t *testing.T) { + err := validatePlace(strings.Repeat("a", 201)) + assert.Error(t, err) + }) +} + +func TestIntereractor_validateDate(t *testing.T) { + t.Run("success", func(t *testing.T) { + future := time.Now().AddDate(1, 0, 0) + err := validateDate(&future) + assert.NoError(t, err) + }) + + t.Run("failure_空値", func(t *testing.T) { + err := validateDate(nil) + assert.Error(t, err) + }) + + t.Run("failure_過去の日付を指定", func(t *testing.T) { + past := time.Date(1990, 9, 1, 12, 0, 0, 0, time.Local) + err := validateDate(&past) + assert.Error(t, err) + }) +} + +func TestIntereractor_validateTags(t *testing.T) { + t.Run("success", func(t *testing.T) { + tags := []string{"sample1", "sample2", "sample3"} + err := validateTags(tags) + assert.NoError(t, err) + }) + + t.Run("failure_エラー混じり", func(t *testing.T) { + tags := []string{"sample1", "sample2", strings.Repeat("a", 101)} + err := validateTags(tags) + assert.Error(t, err) + }) +} + +func TestIntereractor_validateTag(t *testing.T) { + t.Run("success", func(t *testing.T) { + err := validateTag("sampleTag") + assert.NoError(t, err) + }) + + t.Run("success_文字列制限ぴったり", func(t *testing.T) { + err := validateTag(strings.Repeat("a", 100)) + assert.NoError(t, err) + }) + + t.Run("failure_空値", func(t *testing.T) { + err := validateTag("") + assert.Error(t, err) + }) + + t.Run("failure_文字列超過", func(t *testing.T) { + err := validateTag(strings.Repeat("a", 101)) + assert.Error(t, err) + }) +} diff --git a/pkg/domain/entity/place/entity.go b/pkg/domain/entity/place/entity.go new file mode 100644 index 0000000..f8ce875 --- /dev/null +++ b/pkg/domain/entity/place/entity.go @@ -0,0 +1,13 @@ +package place + +import "time" + +type Entity struct { + ID int + Name string + CreatedAt *time.Time + UpdatedAt *time.Time + DeletedAt *time.Time +} + +type EntitySlice []*Entity diff --git a/pkg/domain/entity/tag/entity.go b/pkg/domain/entity/tag/entity.go new file mode 100644 index 0000000..c6e5feb --- /dev/null +++ b/pkg/domain/entity/tag/entity.go @@ -0,0 +1,13 @@ +package tag + +import "time" + +type Entity struct { + ID int + Name string + CreatedAt *time.Time + UpdatedAt *time.Time + DeletedAt *time.Time +} + +type EntitySlice []*Entity diff --git a/pkg/domain/entity/wishcard/entity.go b/pkg/domain/entity/wishcard/entity.go new file mode 100644 index 0000000..27e674c --- /dev/null +++ b/pkg/domain/entity/wishcard/entity.go @@ -0,0 +1,24 @@ +package wishcard + +import ( + "time" + "wantum/pkg/domain/entity/place" + "wantum/pkg/domain/entity/tag" + "wantum/pkg/domain/entity/user" +) + +type Entity struct { + ID int + Author *user.Entity + Activity string + Description string + Date *time.Time + DoneAt *time.Time + CreatedAt *time.Time + UpdatedAt *time.Time + DeletedAt *time.Time + Place *place.Entity + Tags tag.EntitySlice +} + +type EntitySlice []*Entity diff --git a/pkg/domain/repository/place/mock_place/mock_repository.go b/pkg/domain/repository/place/mock_place/mock_repository.go new file mode 100644 index 0000000..dba258a --- /dev/null +++ b/pkg/domain/repository/place/mock_place/mock_repository.go @@ -0,0 +1,152 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/domain/repository/place/repository.go + +// Package mock_place is a generated GoMock package. +package mock_place + +import ( + context "context" + gomock "github.com/golang/mock/gomock" + reflect "reflect" + time "time" + place "wantum/pkg/domain/entity/place" + repository "wantum/pkg/domain/repository" +) + +// MockRepository is a mock of Repository interface +type MockRepository struct { + ctrl *gomock.Controller + recorder *MockRepositoryMockRecorder +} + +// MockRepositoryMockRecorder is the mock recorder for MockRepository +type MockRepositoryMockRecorder struct { + mock *MockRepository +} + +// NewMockRepository creates a new mock instance +func NewMockRepository(ctrl *gomock.Controller) *MockRepository { + mock := &MockRepository{ctrl: ctrl} + mock.recorder = &MockRepositoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder { + return m.recorder +} + +// Insert mocks base method +func (m *MockRepository) Insert(ctx context.Context, masterTx repository.MasterTx, place *place.Entity) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Insert", ctx, masterTx, place) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Insert indicates an expected call of Insert +func (mr *MockRepositoryMockRecorder) Insert(ctx, masterTx, place interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockRepository)(nil).Insert), ctx, masterTx, place) +} + +// Update mocks base method +func (m *MockRepository) Update(ctx context.Context, masterTx repository.MasterTx, place *place.Entity) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", ctx, masterTx, place) + ret0, _ := ret[0].(error) + return ret0 +} + +// Update indicates an expected call of Update +func (mr *MockRepositoryMockRecorder) Update(ctx, masterTx, place interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockRepository)(nil).Update), ctx, masterTx, place) +} + +// UpdateName mocks base method +func (m *MockRepository) UpdateName(ctx context.Context, masterTx repository.MasterTx, placeID int, name string, updatedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateName", ctx, masterTx, placeID, name, updatedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateName indicates an expected call of UpdateName +func (mr *MockRepositoryMockRecorder) UpdateName(ctx, masterTx, placeID, name, updatedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateName", reflect.TypeOf((*MockRepository)(nil).UpdateName), ctx, masterTx, placeID, name, updatedAt) +} + +// Delete mocks base method +func (m *MockRepository) Delete(ctx context.Context, masterTx repository.MasterTx, place *place.Entity) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, masterTx, place) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete +func (mr *MockRepositoryMockRecorder) Delete(ctx, masterTx, place interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockRepository)(nil).Delete), ctx, masterTx, place) +} + +// UpDeleteFlag mocks base method +func (m *MockRepository) UpDeleteFlag(ctx context.Context, masterTx repository.MasterTx, placeID int, updatedAt, deletedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpDeleteFlag", ctx, masterTx, placeID, updatedAt, deletedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpDeleteFlag indicates an expected call of UpDeleteFlag +func (mr *MockRepositoryMockRecorder) UpDeleteFlag(ctx, masterTx, placeID, updatedAt, deletedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpDeleteFlag", reflect.TypeOf((*MockRepository)(nil).UpDeleteFlag), ctx, masterTx, placeID, updatedAt, deletedAt) +} + +// DownDeleteFlag mocks base method +func (m *MockRepository) DownDeleteFlag(ctx context.Context, masterTx repository.MasterTx, placeID int, updatedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DownDeleteFlag", ctx, masterTx, placeID, updatedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// DownDeleteFlag indicates an expected call of DownDeleteFlag +func (mr *MockRepositoryMockRecorder) DownDeleteFlag(ctx, masterTx, placeID, updatedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownDeleteFlag", reflect.TypeOf((*MockRepository)(nil).DownDeleteFlag), ctx, masterTx, placeID, updatedAt) +} + +// SelectByID mocks base method +func (m *MockRepository) SelectByID(ctx context.Context, masterTx repository.MasterTx, placeID int) (*place.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SelectByID", ctx, masterTx, placeID) + ret0, _ := ret[0].(*place.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SelectByID indicates an expected call of SelectByID +func (mr *MockRepositoryMockRecorder) SelectByID(ctx, masterTx, placeID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectByID", reflect.TypeOf((*MockRepository)(nil).SelectByID), ctx, masterTx, placeID) +} + +// SelectAll mocks base method +func (m *MockRepository) SelectAll(ctx context.Context, masterTx repository.MasterTx) (place.EntitySlice, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SelectAll", ctx, masterTx) + ret0, _ := ret[0].(place.EntitySlice) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SelectAll indicates an expected call of SelectAll +func (mr *MockRepositoryMockRecorder) SelectAll(ctx, masterTx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectAll", reflect.TypeOf((*MockRepository)(nil).SelectAll), ctx, masterTx) +} diff --git a/pkg/domain/repository/place/repository.go b/pkg/domain/repository/place/repository.go new file mode 100644 index 0000000..e069e9e --- /dev/null +++ b/pkg/domain/repository/place/repository.go @@ -0,0 +1,19 @@ +package place + +import ( + "context" + "time" + "wantum/pkg/domain/entity/place" + "wantum/pkg/domain/repository" +) + +type Repository interface { + Insert(ctx context.Context, masterTx repository.MasterTx, place *place.Entity) (int, error) + Update(ctx context.Context, masterTx repository.MasterTx, place *place.Entity) error + UpdateName(ctx context.Context, masterTx repository.MasterTx, placeID int, name string, updatedAt *time.Time) error + Delete(ctx context.Context, masterTx repository.MasterTx, place *place.Entity) error + UpDeleteFlag(ctx context.Context, masterTx repository.MasterTx, placeID int, updatedAt, deletedAt *time.Time) error + DownDeleteFlag(ctx context.Context, masterTx repository.MasterTx, placeID int, updatedAt *time.Time) error + SelectByID(ctx context.Context, masterTx repository.MasterTx, placeID int) (*place.Entity, error) + SelectAll(ctx context.Context, masterTx repository.MasterTx) (place.EntitySlice, error) +} diff --git a/pkg/domain/repository/tag/mock_tag/mock_repository.go b/pkg/domain/repository/tag/mock_tag/mock_repository.go new file mode 100644 index 0000000..89bab3c --- /dev/null +++ b/pkg/domain/repository/tag/mock_tag/mock_repository.go @@ -0,0 +1,169 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/domain/repository/tag/repository.go + +// Package mock_tag is a generated GoMock package. +package mock_tag + +import ( + context "context" + gomock "github.com/golang/mock/gomock" + reflect "reflect" + time "time" + tag "wantum/pkg/domain/entity/tag" + repository "wantum/pkg/domain/repository" +) + +// MockRepository is a mock of Repository interface +type MockRepository struct { + ctrl *gomock.Controller + recorder *MockRepositoryMockRecorder +} + +// MockRepositoryMockRecorder is the mock recorder for MockRepository +type MockRepositoryMockRecorder struct { + mock *MockRepository +} + +// NewMockRepository creates a new mock instance +func NewMockRepository(ctrl *gomock.Controller) *MockRepository { + mock := &MockRepository{ctrl: ctrl} + mock.recorder = &MockRepositoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder { + return m.recorder +} + +// Insert mocks base method +func (m *MockRepository) Insert(ctx context.Context, masterTx repository.MasterTx, tag *tag.Entity) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Insert", ctx, masterTx, tag) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Insert indicates an expected call of Insert +func (mr *MockRepositoryMockRecorder) Insert(ctx, masterTx, tag interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockRepository)(nil).Insert), ctx, masterTx, tag) +} + +// UpDeleteFlag mocks base method +func (m *MockRepository) UpDeleteFlag(ctx context.Context, masterTx repository.MasterTx, tagID int, updatedAt, deletedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpDeleteFlag", ctx, masterTx, tagID, updatedAt, deletedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpDeleteFlag indicates an expected call of UpDeleteFlag +func (mr *MockRepositoryMockRecorder) UpDeleteFlag(ctx, masterTx, tagID, updatedAt, deletedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpDeleteFlag", reflect.TypeOf((*MockRepository)(nil).UpDeleteFlag), ctx, masterTx, tagID, updatedAt, deletedAt) +} + +// DownDeleteFlag mocks base method +func (m *MockRepository) DownDeleteFlag(ctx context.Context, masterTx repository.MasterTx, tagID int, updatedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DownDeleteFlag", ctx, masterTx, tagID, updatedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// DownDeleteFlag indicates an expected call of DownDeleteFlag +func (mr *MockRepositoryMockRecorder) DownDeleteFlag(ctx, masterTx, tagID, updatedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownDeleteFlag", reflect.TypeOf((*MockRepository)(nil).DownDeleteFlag), ctx, masterTx, tagID, updatedAt) +} + +// Delete mocks base method +func (m *MockRepository) Delete(ctx context.Context, masterTx repository.MasterTx, tag *tag.Entity) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, masterTx, tag) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete +func (mr *MockRepositoryMockRecorder) Delete(ctx, masterTx, tag interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockRepository)(nil).Delete), ctx, masterTx, tag) +} + +// SelectByID mocks base method +func (m *MockRepository) SelectByID(ctx context.Context, masterTx repository.MasterTx, tagID int) (*tag.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SelectByID", ctx, masterTx, tagID) + ret0, _ := ret[0].(*tag.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SelectByID indicates an expected call of SelectByID +func (mr *MockRepositoryMockRecorder) SelectByID(ctx, masterTx, tagID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectByID", reflect.TypeOf((*MockRepository)(nil).SelectByID), ctx, masterTx, tagID) +} + +// SelectByIDs mocks base method +func (m *MockRepository) SelectByIDs(ctx context.Context, masterTx repository.MasterTx, tagIDs []int) (tag.EntitySlice, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SelectByIDs", ctx, masterTx, tagIDs) + ret0, _ := ret[0].(tag.EntitySlice) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SelectByIDs indicates an expected call of SelectByIDs +func (mr *MockRepositoryMockRecorder) SelectByIDs(ctx, masterTx, tagIDs interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectByIDs", reflect.TypeOf((*MockRepository)(nil).SelectByIDs), ctx, masterTx, tagIDs) +} + +// SelectByName mocks base method +func (m *MockRepository) SelectByName(ctx context.Context, masterTx repository.MasterTx, name string) (*tag.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SelectByName", ctx, masterTx, name) + ret0, _ := ret[0].(*tag.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SelectByName indicates an expected call of SelectByName +func (mr *MockRepositoryMockRecorder) SelectByName(ctx, masterTx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectByName", reflect.TypeOf((*MockRepository)(nil).SelectByName), ctx, masterTx, name) +} + +// SelectByWishCardID mocks base method +func (m *MockRepository) SelectByWishCardID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (tag.EntitySlice, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SelectByWishCardID", ctx, masterTx, wishCardID) + ret0, _ := ret[0].(tag.EntitySlice) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SelectByWishCardID indicates an expected call of SelectByWishCardID +func (mr *MockRepositoryMockRecorder) SelectByWishCardID(ctx, masterTx, wishCardID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectByWishCardID", reflect.TypeOf((*MockRepository)(nil).SelectByWishCardID), ctx, masterTx, wishCardID) +} + +// SelectByMemoryID mocks base method +func (m *MockRepository) SelectByMemoryID(ctx context.Context, masterTx repository.MasterTx, memoryID int) (tag.EntitySlice, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SelectByMemoryID", ctx, masterTx, memoryID) + ret0, _ := ret[0].(tag.EntitySlice) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SelectByMemoryID indicates an expected call of SelectByMemoryID +func (mr *MockRepositoryMockRecorder) SelectByMemoryID(ctx, masterTx, memoryID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectByMemoryID", reflect.TypeOf((*MockRepository)(nil).SelectByMemoryID), ctx, masterTx, memoryID) +} diff --git a/pkg/domain/repository/tag/repository.go b/pkg/domain/repository/tag/repository.go new file mode 100644 index 0000000..9938c28 --- /dev/null +++ b/pkg/domain/repository/tag/repository.go @@ -0,0 +1,20 @@ +package tag + +import ( + "context" + "time" + "wantum/pkg/domain/entity/tag" + "wantum/pkg/domain/repository" +) + +type Repository interface { + Insert(ctx context.Context, masterTx repository.MasterTx, tag *tag.Entity) (int, error) + UpDeleteFlag(ctx context.Context, masterTx repository.MasterTx, tagID int, updatedAt, deletedAt *time.Time) error + DownDeleteFlag(ctx context.Context, masterTx repository.MasterTx, tagID int, updatedAt *time.Time) error + Delete(ctx context.Context, masterTx repository.MasterTx, tag *tag.Entity) error + SelectByID(ctx context.Context, masterTx repository.MasterTx, tagID int) (*tag.Entity, error) + SelectByIDs(ctx context.Context, masterTx repository.MasterTx, tagIDs []int) (tag.EntitySlice, error) + SelectByName(ctx context.Context, masterTx repository.MasterTx, name string) (*tag.Entity, error) + SelectByWishCardID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (tag.EntitySlice, error) + SelectByMemoryID(ctx context.Context, masterTx repository.MasterTx, memoryID int) (tag.EntitySlice, error) +} diff --git a/pkg/domain/repository/wishcard/mock_wish_card/mock_repository.go b/pkg/domain/repository/wishcard/mock_wish_card/mock_repository.go new file mode 100644 index 0000000..2b10050 --- /dev/null +++ b/pkg/domain/repository/wishcard/mock_wish_card/mock_repository.go @@ -0,0 +1,265 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/domain/repository/wishcard/repository.go + +// Package mock_wish_card is a generated GoMock package. +package mock_wish_card + +import ( + context "context" + gomock "github.com/golang/mock/gomock" + reflect "reflect" + time "time" + wishcard "wantum/pkg/domain/entity/wishcard" + repository "wantum/pkg/domain/repository" +) + +// MockRepository is a mock of Repository interface +type MockRepository struct { + ctrl *gomock.Controller + recorder *MockRepositoryMockRecorder +} + +// MockRepositoryMockRecorder is the mock recorder for MockRepository +type MockRepositoryMockRecorder struct { + mock *MockRepository +} + +// NewMockRepository creates a new mock instance +func NewMockRepository(ctrl *gomock.Controller) *MockRepository { + mock := &MockRepository{ctrl: ctrl} + mock.recorder = &MockRepositoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder { + return m.recorder +} + +// Insert mocks base method +func (m *MockRepository) Insert(ctx context.Context, masterTx repository.MasterTx, wishCard *wishcard.Entity, categoryID int) (int, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Insert", ctx, masterTx, wishCard, categoryID) + ret0, _ := ret[0].(int) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Insert indicates an expected call of Insert +func (mr *MockRepositoryMockRecorder) Insert(ctx, masterTx, wishCard, categoryID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockRepository)(nil).Insert), ctx, masterTx, wishCard, categoryID) +} + +// Update mocks base method +func (m *MockRepository) Update(ctx context.Context, masterTx repository.MasterTx, wishCard *wishcard.Entity) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", ctx, masterTx, wishCard) + ret0, _ := ret[0].(error) + return ret0 +} + +// Update indicates an expected call of Update +func (mr *MockRepositoryMockRecorder) Update(ctx, masterTx, wishCard interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockRepository)(nil).Update), ctx, masterTx, wishCard) +} + +// UpdateActivity mocks base method +func (m *MockRepository) UpdateActivity(ctx context.Context, masterTx repository.MasterTx, wishCardID int, activity string, updatedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateActivity", ctx, masterTx, wishCardID, activity, updatedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateActivity indicates an expected call of UpdateActivity +func (mr *MockRepositoryMockRecorder) UpdateActivity(ctx, masterTx, wishCardID, activity, updatedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateActivity", reflect.TypeOf((*MockRepository)(nil).UpdateActivity), ctx, masterTx, wishCardID, activity, updatedAt) +} + +// UpdateDescription mocks base method +func (m *MockRepository) UpdateDescription(ctx context.Context, masterTx repository.MasterTx, wishCardID int, description string, updatedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateDescription", ctx, masterTx, wishCardID, description, updatedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateDescription indicates an expected call of UpdateDescription +func (mr *MockRepositoryMockRecorder) UpdateDescription(ctx, masterTx, wishCardID, description, updatedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateDescription", reflect.TypeOf((*MockRepository)(nil).UpdateDescription), ctx, masterTx, wishCardID, description, updatedAt) +} + +// UpdateDate mocks base method +func (m *MockRepository) UpdateDate(ctx context.Context, masterTx repository.MasterTx, wishCardID int, date, updatedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateDate", ctx, masterTx, wishCardID, date, updatedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateDate indicates an expected call of UpdateDate +func (mr *MockRepositoryMockRecorder) UpdateDate(ctx, masterTx, wishCardID, date, updatedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateDate", reflect.TypeOf((*MockRepository)(nil).UpdateDate), ctx, masterTx, wishCardID, date, updatedAt) +} + +// UpdateDoneAt mocks base method +func (m *MockRepository) UpdateDoneAt(ctx context.Context, masterTx repository.MasterTx, wishCardID int, doneAt, updatedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateDoneAt", ctx, masterTx, wishCardID, doneAt, updatedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateDoneAt indicates an expected call of UpdateDoneAt +func (mr *MockRepositoryMockRecorder) UpdateDoneAt(ctx, masterTx, wishCardID, doneAt, updatedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateDoneAt", reflect.TypeOf((*MockRepository)(nil).UpdateDoneAt), ctx, masterTx, wishCardID, doneAt, updatedAt) +} + +// UpdateUserID mocks base method +func (m *MockRepository) UpdateUserID(ctx context.Context, masterTx repository.MasterTx, wishCardID, userID int, updatedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserID", ctx, masterTx, wishCardID, userID, updatedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateUserID indicates an expected call of UpdateUserID +func (mr *MockRepositoryMockRecorder) UpdateUserID(ctx, masterTx, wishCardID, userID, updatedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserID", reflect.TypeOf((*MockRepository)(nil).UpdateUserID), ctx, masterTx, wishCardID, userID, updatedAt) +} + +// UpdatePlaceID mocks base method +func (m *MockRepository) UpdatePlaceID(ctx context.Context, masterTx repository.MasterTx, wishCardID, placeID int, updatedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdatePlaceID", ctx, masterTx, wishCardID, placeID, updatedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdatePlaceID indicates an expected call of UpdatePlaceID +func (mr *MockRepositoryMockRecorder) UpdatePlaceID(ctx, masterTx, wishCardID, placeID, updatedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePlaceID", reflect.TypeOf((*MockRepository)(nil).UpdatePlaceID), ctx, masterTx, wishCardID, placeID, updatedAt) +} + +// UpdateCategoryID mocks base method +func (m *MockRepository) UpdateCategoryID(ctx context.Context, masterTx repository.MasterTx, wishCardID, categoryID int, updatedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateCategoryID", ctx, masterTx, wishCardID, categoryID, updatedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateCategoryID indicates an expected call of UpdateCategoryID +func (mr *MockRepositoryMockRecorder) UpdateCategoryID(ctx, masterTx, wishCardID, categoryID, updatedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateCategoryID", reflect.TypeOf((*MockRepository)(nil).UpdateCategoryID), ctx, masterTx, wishCardID, categoryID, updatedAt) +} + +// UpdateWithCategoryID mocks base method +func (m *MockRepository) UpdateWithCategoryID(ctx context.Context, masterTx repository.MasterTx, wishCard *wishcard.Entity, categoryID int) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWithCategoryID", ctx, masterTx, wishCard, categoryID) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateWithCategoryID indicates an expected call of UpdateWithCategoryID +func (mr *MockRepositoryMockRecorder) UpdateWithCategoryID(ctx, masterTx, wishCard, categoryID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWithCategoryID", reflect.TypeOf((*MockRepository)(nil).UpdateWithCategoryID), ctx, masterTx, wishCard, categoryID) +} + +// UpDeleteFlag mocks base method +func (m *MockRepository) UpDeleteFlag(ctx context.Context, masterTx repository.MasterTx, wishCardID int, updatedAt, deletedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpDeleteFlag", ctx, masterTx, wishCardID, updatedAt, deletedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpDeleteFlag indicates an expected call of UpDeleteFlag +func (mr *MockRepositoryMockRecorder) UpDeleteFlag(ctx, masterTx, wishCardID, updatedAt, deletedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpDeleteFlag", reflect.TypeOf((*MockRepository)(nil).UpDeleteFlag), ctx, masterTx, wishCardID, updatedAt, deletedAt) +} + +// DownDeleteFlag mocks base method +func (m *MockRepository) DownDeleteFlag(ctx context.Context, masterTx repository.MasterTx, wishCardID int, updatedAt *time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DownDeleteFlag", ctx, masterTx, wishCardID, updatedAt) + ret0, _ := ret[0].(error) + return ret0 +} + +// DownDeleteFlag indicates an expected call of DownDeleteFlag +func (mr *MockRepositoryMockRecorder) DownDeleteFlag(ctx, masterTx, wishCardID, updatedAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownDeleteFlag", reflect.TypeOf((*MockRepository)(nil).DownDeleteFlag), ctx, masterTx, wishCardID, updatedAt) +} + +// Delete mocks base method +func (m *MockRepository) Delete(ctx context.Context, masterTx repository.MasterTx, wishCard *wishcard.Entity) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, masterTx, wishCard) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete +func (mr *MockRepositoryMockRecorder) Delete(ctx, masterTx, wishCard interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockRepository)(nil).Delete), ctx, masterTx, wishCard) +} + +// SelectByID mocks base method +func (m *MockRepository) SelectByID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SelectByID", ctx, masterTx, wishCardID) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SelectByID indicates an expected call of SelectByID +func (mr *MockRepositoryMockRecorder) SelectByID(ctx, masterTx, wishCardID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectByID", reflect.TypeOf((*MockRepository)(nil).SelectByID), ctx, masterTx, wishCardID) +} + +// SelectByIDs mocks base method +func (m *MockRepository) SelectByIDs(ctx context.Context, masterTx repository.MasterTx, wishCardIDs []int) (wishcard.EntitySlice, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SelectByIDs", ctx, masterTx, wishCardIDs) + ret0, _ := ret[0].(wishcard.EntitySlice) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SelectByIDs indicates an expected call of SelectByIDs +func (mr *MockRepositoryMockRecorder) SelectByIDs(ctx, masterTx, wishCardIDs interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectByIDs", reflect.TypeOf((*MockRepository)(nil).SelectByIDs), ctx, masterTx, wishCardIDs) +} + +// SelectByCategoryID mocks base method +func (m *MockRepository) SelectByCategoryID(ctx context.Context, masterTx repository.MasterTx, categryID int) (wishcard.EntitySlice, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SelectByCategoryID", ctx, masterTx, categryID) + ret0, _ := ret[0].(wishcard.EntitySlice) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// SelectByCategoryID indicates an expected call of SelectByCategoryID +func (mr *MockRepositoryMockRecorder) SelectByCategoryID(ctx, masterTx, categryID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectByCategoryID", reflect.TypeOf((*MockRepository)(nil).SelectByCategoryID), ctx, masterTx, categryID) +} diff --git a/pkg/domain/repository/wishcard/repository.go b/pkg/domain/repository/wishcard/repository.go new file mode 100644 index 0000000..2f44b16 --- /dev/null +++ b/pkg/domain/repository/wishcard/repository.go @@ -0,0 +1,27 @@ +package wishcard + +import ( + "context" + "time" + "wantum/pkg/domain/entity/wishcard" + "wantum/pkg/domain/repository" +) + +type Repository interface { + Insert(ctx context.Context, masterTx repository.MasterTx, wishCard *wishcard.Entity, categoryID int) (int, error) + Update(ctx context.Context, masterTx repository.MasterTx, wishCard *wishcard.Entity) error + UpdateActivity(ctx context.Context, masterTx repository.MasterTx, wishCardID int, activity string, updatedAt *time.Time) error + UpdateDescription(ctx context.Context, masterTx repository.MasterTx, wishCardID int, description string, updatedAt *time.Time) error + UpdateDate(ctx context.Context, masterTx repository.MasterTx, wishCardID int, date, updatedAt *time.Time) error + UpdateDoneAt(ctx context.Context, masterTx repository.MasterTx, wishCardID int, doneAt, updatedAt *time.Time) error + UpdateUserID(ctx context.Context, masterTx repository.MasterTx, wishCardID int, userID int, updatedAt *time.Time) error + UpdatePlaceID(ctx context.Context, masterTx repository.MasterTx, wishCardID int, placeID int, updatedAt *time.Time) error + UpdateCategoryID(ctx context.Context, masterTx repository.MasterTx, wishCardID int, categoryID int, updatedAt *time.Time) error + UpdateWithCategoryID(ctx context.Context, masterTx repository.MasterTx, wishCard *wishcard.Entity, categoryID int) error + UpDeleteFlag(ctx context.Context, masterTx repository.MasterTx, wishCardID int, updatedAt, deletedAt *time.Time) error + DownDeleteFlag(ctx context.Context, masterTx repository.MasterTx, wishCardID int, updatedAt *time.Time) error + Delete(ctx context.Context, masterTx repository.MasterTx, wishCard *wishcard.Entity) error + SelectByID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (*wishcard.Entity, error) + SelectByIDs(ctx context.Context, masterTx repository.MasterTx, wishCardIDs []int) (wishcard.EntitySlice, error) + SelectByCategoryID(ctx context.Context, masterTx repository.MasterTx, categryID int) (wishcard.EntitySlice, error) +} diff --git a/pkg/domain/repository/wishcardtag/mock_wish_card_tag/mock_repository.go b/pkg/domain/repository/wishcardtag/mock_wish_card_tag/mock_repository.go new file mode 100644 index 0000000..0cba507 --- /dev/null +++ b/pkg/domain/repository/wishcardtag/mock_wish_card_tag/mock_repository.go @@ -0,0 +1,105 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/domain/repository/wishcardtag/repository.go + +// Package mock_wish_card_tag is a generated GoMock package. +package mock_wish_card_tag + +import ( + context "context" + gomock "github.com/golang/mock/gomock" + reflect "reflect" + repository "wantum/pkg/domain/repository" +) + +// MockRepository is a mock of Repository interface +type MockRepository struct { + ctrl *gomock.Controller + recorder *MockRepositoryMockRecorder +} + +// MockRepositoryMockRecorder is the mock recorder for MockRepository +type MockRepositoryMockRecorder struct { + mock *MockRepository +} + +// NewMockRepository creates a new mock instance +func NewMockRepository(ctrl *gomock.Controller) *MockRepository { + mock := &MockRepository{ctrl: ctrl} + mock.recorder = &MockRepositoryMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder { + return m.recorder +} + +// Insert mocks base method +func (m *MockRepository) Insert(ctx context.Context, masterTx repository.MasterTx, wishCardID, tagID int) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Insert", ctx, masterTx, wishCardID, tagID) + ret0, _ := ret[0].(error) + return ret0 +} + +// Insert indicates an expected call of Insert +func (mr *MockRepositoryMockRecorder) Insert(ctx, masterTx, wishCardID, tagID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockRepository)(nil).Insert), ctx, masterTx, wishCardID, tagID) +} + +// BulkInsert mocks base method +func (m *MockRepository) BulkInsert(ctx context.Context, masterTx repository.MasterTx, wishCardID int, tagIDs []int) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "BulkInsert", ctx, masterTx, wishCardID, tagIDs) + ret0, _ := ret[0].(error) + return ret0 +} + +// BulkInsert indicates an expected call of BulkInsert +func (mr *MockRepositoryMockRecorder) BulkInsert(ctx, masterTx, wishCardID, tagIDs interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BulkInsert", reflect.TypeOf((*MockRepository)(nil).BulkInsert), ctx, masterTx, wishCardID, tagIDs) +} + +// Delete mocks base method +func (m *MockRepository) Delete(ctx context.Context, masterTx repository.MasterTx, wishCardID, tagID int) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, masterTx, wishCardID, tagID) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete +func (mr *MockRepositoryMockRecorder) Delete(ctx, masterTx, wishCardID, tagID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockRepository)(nil).Delete), ctx, masterTx, wishCardID, tagID) +} + +// DeleteByWishCardID mocks base method +func (m *MockRepository) DeleteByWishCardID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteByWishCardID", ctx, masterTx, wishCardID) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteByWishCardID indicates an expected call of DeleteByWishCardID +func (mr *MockRepositoryMockRecorder) DeleteByWishCardID(ctx, masterTx, wishCardID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteByWishCardID", reflect.TypeOf((*MockRepository)(nil).DeleteByWishCardID), ctx, masterTx, wishCardID) +} + +// DeleteByIDs mocks base method +func (m *MockRepository) DeleteByIDs(ctx context.Context, masterTx repository.MasterTx, wishCardID int, tagIDs []int) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteByIDs", ctx, masterTx, wishCardID, tagIDs) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteByIDs indicates an expected call of DeleteByIDs +func (mr *MockRepositoryMockRecorder) DeleteByIDs(ctx, masterTx, wishCardID, tagIDs interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteByIDs", reflect.TypeOf((*MockRepository)(nil).DeleteByIDs), ctx, masterTx, wishCardID, tagIDs) +} diff --git a/pkg/domain/repository/wishcardtag/repository.go b/pkg/domain/repository/wishcardtag/repository.go new file mode 100644 index 0000000..eed1126 --- /dev/null +++ b/pkg/domain/repository/wishcardtag/repository.go @@ -0,0 +1,14 @@ +package wishcardtag + +import ( + "context" + "wantum/pkg/domain/repository" +) + +type Repository interface { + Insert(ctx context.Context, masterTx repository.MasterTx, wishCardID, tagID int) error + BulkInsert(ctx context.Context, masterTx repository.MasterTx, wishCardID int, tagIDs []int) error + Delete(ctx context.Context, masterTx repository.MasterTx, wishCardID, tagID int) error + DeleteByWishCardID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) error + DeleteByIDs(ctx context.Context, masterTx repository.MasterTx, wishCardID int, tagIDs []int) error +} diff --git a/pkg/domain/service/place/mock_place/mock_service.go b/pkg/domain/service/place/mock_place/mock_service.go new file mode 100644 index 0000000..6043d89 --- /dev/null +++ b/pkg/domain/service/place/mock_place/mock_service.go @@ -0,0 +1,126 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/domain/service/place/service.go + +// Package mock_place is a generated GoMock package. +package mock_place + +import ( + context "context" + gomock "github.com/golang/mock/gomock" + reflect "reflect" + place "wantum/pkg/domain/entity/place" + repository "wantum/pkg/domain/repository" +) + +// MockService is a mock of Service interface +type MockService struct { + ctrl *gomock.Controller + recorder *MockServiceMockRecorder +} + +// MockServiceMockRecorder is the mock recorder for MockService +type MockServiceMockRecorder struct { + mock *MockService +} + +// NewMockService creates a new mock instance +func NewMockService(ctrl *gomock.Controller) *MockService { + mock := &MockService{ctrl: ctrl} + mock.recorder = &MockServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockService) EXPECT() *MockServiceMockRecorder { + return m.recorder +} + +// Create mocks base method +func (m *MockService) Create(ctx context.Context, masterTx repository.MasterTx, name string) (*place.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", ctx, masterTx, name) + ret0, _ := ret[0].(*place.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Create indicates an expected call of Create +func (mr *MockServiceMockRecorder) Create(ctx, masterTx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockService)(nil).Create), ctx, masterTx, name) +} + +// Update mocks base method +func (m *MockService) Update(ctx context.Context, masterTx repository.MasterTx, placeID int, name string) (*place.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", ctx, masterTx, placeID, name) + ret0, _ := ret[0].(*place.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Update indicates an expected call of Update +func (mr *MockServiceMockRecorder) Update(ctx, masterTx, placeID, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockService)(nil).Update), ctx, masterTx, placeID, name) +} + +// UpdateName mocks base method +func (m *MockService) UpdateName(ctx context.Context, masterTx repository.MasterTx, placeID int, name string) (*place.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateName", ctx, masterTx, placeID, name) + ret0, _ := ret[0].(*place.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateName indicates an expected call of UpdateName +func (mr *MockServiceMockRecorder) UpdateName(ctx, masterTx, placeID, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateName", reflect.TypeOf((*MockService)(nil).UpdateName), ctx, masterTx, placeID, name) +} + +// Delete mocks base method +func (m *MockService) Delete(ctx context.Context, masterTx repository.MasterTx, placeID int) (*place.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, masterTx, placeID) + ret0, _ := ret[0].(*place.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete +func (mr *MockServiceMockRecorder) Delete(ctx, masterTx, placeID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockService)(nil).Delete), ctx, masterTx, placeID) +} + +// GetByID mocks base method +func (m *MockService) GetByID(ctx context.Context, masterTx repository.MasterTx, placeID int) (*place.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetByID", ctx, masterTx, placeID) + ret0, _ := ret[0].(*place.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetByID indicates an expected call of GetByID +func (mr *MockServiceMockRecorder) GetByID(ctx, masterTx, placeID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByID", reflect.TypeOf((*MockService)(nil).GetByID), ctx, masterTx, placeID) +} + +// GetAll mocks base method +func (m *MockService) GetAll(ctx context.Context, masterTx repository.MasterTx) (place.EntitySlice, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAll", ctx, masterTx) + ret0, _ := ret[0].(place.EntitySlice) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAll indicates an expected call of GetAll +func (mr *MockServiceMockRecorder) GetAll(ctx, masterTx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAll", reflect.TypeOf((*MockService)(nil).GetAll), ctx, masterTx) +} diff --git a/pkg/domain/service/place/service.go b/pkg/domain/service/place/service.go new file mode 100644 index 0000000..24c1798 --- /dev/null +++ b/pkg/domain/service/place/service.go @@ -0,0 +1,107 @@ +package place + +import ( + "context" + "time" + placeEntity "wantum/pkg/domain/entity/place" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/repository/place" + "wantum/pkg/werrors" +) + +type Service interface { + Create(ctx context.Context, masterTx repository.MasterTx, name string) (*placeEntity.Entity, error) + Update(ctx context.Context, masterTx repository.MasterTx, placeID int, name string) (*placeEntity.Entity, error) + UpdateName(ctx context.Context, masterTx repository.MasterTx, placeID int, name string) (*placeEntity.Entity, error) + Delete(ctx context.Context, masterTx repository.MasterTx, placeID int) (*placeEntity.Entity, error) + GetByID(ctx context.Context, masterTx repository.MasterTx, placeID int) (*placeEntity.Entity, error) + GetAll(ctx context.Context, masterTx repository.MasterTx) (placeEntity.EntitySlice, error) +} + +type service struct { + placeRepository place.Repository +} + +func New(repo place.Repository) Service { + return &service{ + placeRepository: repo, + } +} + +func (s *service) Create(ctx context.Context, masterTx repository.MasterTx, name string) (*placeEntity.Entity, error) { + now := time.Now() + place := &placeEntity.Entity{ + Name: name, + CreatedAt: &now, + UpdatedAt: &now, + } + newID, err := s.placeRepository.Insert(ctx, masterTx, place) + if err != nil { + return nil, werrors.Stack(err) + } + place.ID = newID + return place, nil +} + +// WARNING: 空値があった時、元データが消滅する。 +func (s *service) Update(ctx context.Context, masterTx repository.MasterTx, placeID int, name string) (*placeEntity.Entity, error) { + place, err := s.placeRepository.SelectByID(ctx, masterTx, placeID) + if err != nil { + return nil, werrors.Stack(err) + } + + now := time.Now() + place.Name = name + place.UpdatedAt = &now + if err = s.placeRepository.Update(ctx, masterTx, place); err != nil { + return nil, werrors.Stack(err) + } + return place, nil +} + +func (s *service) UpdateName(ctx context.Context, masterTx repository.MasterTx, placeID int, name string) (*placeEntity.Entity, error) { + place, err := s.placeRepository.SelectByID(ctx, masterTx, placeID) + if err != nil { + return nil, werrors.Stack(err) + } + if place == nil { + return nil, werrors.Stack(werrors.PlaceNotFound) + } + now := time.Now() + place.UpdatedAt = &now + place.Name = name + if err = s.placeRepository.UpdateName(ctx, masterTx, placeID, place.Name, place.UpdatedAt); err != nil { + return nil, werrors.Stack(err) + } + return place, nil +} + +func (s *service) Delete(ctx context.Context, masterTx repository.MasterTx, placeID int) (*placeEntity.Entity, error) { + place, err := s.placeRepository.SelectByID(ctx, masterTx, placeID) + if err != nil { + return nil, werrors.Stack(err) + } + now := time.Now() + place.UpdatedAt = &now + place.DeletedAt = &now + if err = s.placeRepository.UpDeleteFlag(ctx, masterTx, place.ID, place.UpdatedAt, place.DeletedAt); err != nil { + return nil, werrors.Stack(err) + } + return place, nil +} + +func (s *service) GetByID(ctx context.Context, masterTx repository.MasterTx, placeID int) (*placeEntity.Entity, error) { + place, err := s.placeRepository.SelectByID(ctx, masterTx, placeID) + if err != nil { + return nil, werrors.Stack(err) + } + return place, nil +} + +func (s *service) GetAll(ctx context.Context, masterTx repository.MasterTx) (placeEntity.EntitySlice, error) { + places, err := s.placeRepository.SelectAll(ctx, masterTx) + if err != nil { + return nil, werrors.Stack(err) + } + return places, nil +} diff --git a/pkg/domain/service/place/service_test.go b/pkg/domain/service/place/service_test.go new file mode 100644 index 0000000..a34a227 --- /dev/null +++ b/pkg/domain/service/place/service_test.go @@ -0,0 +1,188 @@ +package place + +import ( + "context" + "os" + "testing" + "time" + placeEntity "wantum/pkg/domain/entity/place" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/repository/place/mock_place" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +var ( + masterTx repository.MasterTx + dummyDate time.Time + + dummyPlaceID = 1 + dummyPlaceName = "tsushima" +) + +func TestMain(m *testing.M) { + before() + code := m.Run() + os.Exit(code) +} + +func before() { + dummyDate = time.Date(2020, 9, 1, 12, 0, 0, 0, time.Local) + masterTx = repository.NewMockMasterTx() +} + +func TestService_Create(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + repo := mock_place.NewMockRepository(ctrl) + repo.EXPECT().Insert(ctx, masterTx, gomock.Any()).Return(1, nil) + + service := New(repo) + result, err := service.Create(ctx, masterTx, "tokyo") + + assert.NoError(t, err) + assert.NotNil(t, result) +} + +func TestService_Update(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &placeEntity.Entity{ + ID: 1, + Name: "tokyo", + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + repo := mock_place.NewMockRepository(ctrl) + repo.EXPECT().Update(ctx, masterTx, gomock.Any()).Return(nil) + repo.EXPECT().SelectByID(ctx, masterTx, dummyData.ID).Return(dummyData, nil) + + service := New(repo) + result, err := service.Update(ctx, masterTx, dummyData.ID, "shibuya") + + assert.NoError(t, err) + assert.NotNil(t, result) +} + +func TestService_UpdateName(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &placeEntity.Entity{ + ID: 1, + Name: "tokyo", + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + repo := mock_place.NewMockRepository(ctrl) + repo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + repo.EXPECT().UpdateName(ctx, masterTx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + + service := New(repo) + result, err := service.UpdateName(ctx, masterTx, dummyPlaceID, dummyPlaceName) + + assert.NoError(t, err) + assert.NotEqual(t, dummyDate, result.UpdatedAt.Local()) + assert.Equal(t, dummyPlaceName, result.Name) + }) + + t.Run("failure_存在しないデータ", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + repo := mock_place.NewMockRepository(ctrl) + repo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(nil, nil) + + service := New(repo) + _, err := service.UpdateName(ctx, masterTx, dummyPlaceID, dummyPlaceName) + + assert.Error(t, err) + }) +} + +func TestService_Delete(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &placeEntity.Entity{ + ID: 1, + Name: "tokyo", + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + repo := mock_place.NewMockRepository(ctrl) + repo.EXPECT().UpDeleteFlag(ctx, masterTx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + repo.EXPECT().SelectByID(ctx, masterTx, dummyData.ID).Return(dummyData, nil) + + service := New(repo) + result, err := service.Delete(ctx, masterTx, dummyData.ID) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.NotNil(t, result.DeletedAt) +} + +func TestService_GetByID(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &placeEntity.Entity{ + ID: 1, + Name: "tokyo", + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + repo := mock_place.NewMockRepository(ctrl) + repo.EXPECT().SelectByID(ctx, masterTx, dummyData.ID).Return(dummyData, nil) + + service := New(repo) + result, err := service.GetByID(ctx, masterTx, dummyData.ID) + + assert.NoError(t, err) + assert.NotNil(t, result) +} + +func TestService_GetAll(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := placeEntity.EntitySlice{ + &placeEntity.Entity{ + ID: 1, + Name: "tokyo", + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + }, + &placeEntity.Entity{ + ID: 2, + Name: "shibuya", + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: &dummyDate, + }, + } + + repo := mock_place.NewMockRepository(ctrl) + repo.EXPECT().SelectAll(ctx, masterTx).Return(dummyData, nil) + + service := New(repo) + result, err := service.GetAll(ctx, masterTx) + + assert.NoError(t, err) + assert.NotNil(t, result) +} diff --git a/pkg/domain/service/tag/mock_tag/mock_service.go b/pkg/domain/service/tag/mock_tag/mock_service.go new file mode 100644 index 0000000..949220d --- /dev/null +++ b/pkg/domain/service/tag/mock_tag/mock_service.go @@ -0,0 +1,126 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/domain/service/tag/service.go + +// Package mock_tag is a generated GoMock package. +package mock_tag + +import ( + context "context" + gomock "github.com/golang/mock/gomock" + reflect "reflect" + tag "wantum/pkg/domain/entity/tag" + repository "wantum/pkg/domain/repository" +) + +// MockService is a mock of Service interface +type MockService struct { + ctrl *gomock.Controller + recorder *MockServiceMockRecorder +} + +// MockServiceMockRecorder is the mock recorder for MockService +type MockServiceMockRecorder struct { + mock *MockService +} + +// NewMockService creates a new mock instance +func NewMockService(ctrl *gomock.Controller) *MockService { + mock := &MockService{ctrl: ctrl} + mock.recorder = &MockServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockService) EXPECT() *MockServiceMockRecorder { + return m.recorder +} + +// Create mocks base method +func (m *MockService) Create(ctx context.Context, masterTx repository.MasterTx, name string) (*tag.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", ctx, masterTx, name) + ret0, _ := ret[0].(*tag.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Create indicates an expected call of Create +func (mr *MockServiceMockRecorder) Create(ctx, masterTx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockService)(nil).Create), ctx, masterTx, name) +} + +// Delete mocks base method +func (m *MockService) Delete(ctx context.Context, masterTx repository.MasterTx, tagID int) (*tag.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, masterTx, tagID) + ret0, _ := ret[0].(*tag.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Delete indicates an expected call of Delete +func (mr *MockServiceMockRecorder) Delete(ctx, masterTx, tagID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockService)(nil).Delete), ctx, masterTx, tagID) +} + +// GetByID mocks base method +func (m *MockService) GetByID(ctx context.Context, masterTx repository.MasterTx, tagID int) (*tag.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetByID", ctx, masterTx, tagID) + ret0, _ := ret[0].(*tag.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetByID indicates an expected call of GetByID +func (mr *MockServiceMockRecorder) GetByID(ctx, masterTx, tagID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByID", reflect.TypeOf((*MockService)(nil).GetByID), ctx, masterTx, tagID) +} + +// GetByName mocks base method +func (m *MockService) GetByName(ctx context.Context, masterTx repository.MasterTx, name string) (*tag.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetByName", ctx, masterTx, name) + ret0, _ := ret[0].(*tag.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetByName indicates an expected call of GetByName +func (mr *MockServiceMockRecorder) GetByName(ctx, masterTx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByName", reflect.TypeOf((*MockService)(nil).GetByName), ctx, masterTx, name) +} + +// GetByWishCardID mocks base method +func (m *MockService) GetByWishCardID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (tag.EntitySlice, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetByWishCardID", ctx, masterTx, wishCardID) + ret0, _ := ret[0].(tag.EntitySlice) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetByWishCardID indicates an expected call of GetByWishCardID +func (mr *MockServiceMockRecorder) GetByWishCardID(ctx, masterTx, wishCardID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByWishCardID", reflect.TypeOf((*MockService)(nil).GetByWishCardID), ctx, masterTx, wishCardID) +} + +// GetByMemoryID mocks base method +func (m *MockService) GetByMemoryID(ctx context.Context, masterTx repository.MasterTx, memoryID int) (tag.EntitySlice, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetByMemoryID", ctx, masterTx, memoryID) + ret0, _ := ret[0].(tag.EntitySlice) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetByMemoryID indicates an expected call of GetByMemoryID +func (mr *MockServiceMockRecorder) GetByMemoryID(ctx, masterTx, memoryID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByMemoryID", reflect.TypeOf((*MockService)(nil).GetByMemoryID), ctx, masterTx, memoryID) +} diff --git a/pkg/domain/service/tag/service.go b/pkg/domain/service/tag/service.go new file mode 100644 index 0000000..f2508af --- /dev/null +++ b/pkg/domain/service/tag/service.go @@ -0,0 +1,90 @@ +package tag + +import ( + "context" + "time" + tagEntity "wantum/pkg/domain/entity/tag" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/repository/tag" + "wantum/pkg/werrors" +) + +type Service interface { + Create(ctx context.Context, masterTx repository.MasterTx, name string) (*tagEntity.Entity, error) + Delete(ctx context.Context, masterTx repository.MasterTx, tagID int) (*tagEntity.Entity, error) + GetByID(ctx context.Context, masterTx repository.MasterTx, tagID int) (*tagEntity.Entity, error) + GetByName(ctx context.Context, masterTx repository.MasterTx, name string) (*tagEntity.Entity, error) + GetByWishCardID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (tagEntity.EntitySlice, error) + GetByMemoryID(ctx context.Context, masterTx repository.MasterTx, memoryID int) (tagEntity.EntitySlice, error) +} + +type service struct { + tagRepository tag.Repository +} + +func New(repo tag.Repository) Service { + return &service{ + tagRepository: repo, + } +} + +func (s *service) Create(ctx context.Context, masterTx repository.MasterTx, name string) (*tagEntity.Entity, error) { + now := time.Now() + tag := &tagEntity.Entity{ + Name: name, + CreatedAt: &now, + UpdatedAt: &now, + } + newID, err := s.tagRepository.Insert(ctx, masterTx, tag) + if err != nil { + return nil, werrors.Stack(err) + } + tag.ID = newID + return tag, nil +} + +func (s *service) Delete(ctx context.Context, masterTx repository.MasterTx, tagID int) (*tagEntity.Entity, error) { + tag, err := s.tagRepository.SelectByID(ctx, masterTx, tagID) + if err != nil { + return nil, werrors.Stack(err) + } + now := time.Now() + tag.UpdatedAt = &now + tag.DeletedAt = &now + if err = s.tagRepository.UpDeleteFlag(ctx, masterTx, tag.ID, tag.UpdatedAt, tag.DeletedAt); err != nil { + return nil, werrors.Stack(err) + } + return tag, nil +} + +func (s *service) GetByID(ctx context.Context, masterTx repository.MasterTx, tagID int) (*tagEntity.Entity, error) { + tag, err := s.tagRepository.SelectByID(ctx, masterTx, tagID) + if err != nil { + return nil, werrors.Stack(err) + } + return tag, nil +} + +func (s *service) GetByName(ctx context.Context, masterTx repository.MasterTx, name string) (*tagEntity.Entity, error) { + tag, err := s.tagRepository.SelectByName(ctx, masterTx, name) + if err != nil { + return nil, werrors.Stack(err) + } + return tag, nil +} + +func (s *service) GetByWishCardID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (tagEntity.EntitySlice, error) { + tags, err := s.tagRepository.SelectByWishCardID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + return tags, nil +} + +func (s *service) GetByMemoryID(ctx context.Context, masterTx repository.MasterTx, memoryID int) (tagEntity.EntitySlice, error) { + tags, err := s.tagRepository.SelectByMemoryID(ctx, masterTx, memoryID) + if err != nil { + return nil, werrors.Stack(err) + } + return tags, nil +} diff --git a/pkg/domain/service/tag/service_test.go b/pkg/domain/service/tag/service_test.go new file mode 100644 index 0000000..fcbe768 --- /dev/null +++ b/pkg/domain/service/tag/service_test.go @@ -0,0 +1,129 @@ +package tag + +import ( + "context" + "os" + "testing" + "time" + tagEntity "wantum/pkg/domain/entity/tag" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/repository/tag/mock_tag" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +var ( + masterTx repository.MasterTx + dummyDate time.Time + + dummyTag = &tagEntity.Entity{ + ID: 1, + Name: "sampleTag", + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + dummyTagSlice = tagEntity.EntitySlice{ + &tagEntity.Entity{ + ID: 1, + Name: "sampleTag1", + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + }, + &tagEntity.Entity{ + ID: 2, + Name: "sampleTag2", + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + }, + } +) + +func TestMain(m *testing.M) { + before() + code := m.Run() + os.Exit(code) +} + +func before() { + dummyDate = time.Date(2020, 9, 1, 12, 0, 0, 0, time.Local) + masterTx = repository.NewMockMasterTx() +} + +func TestService_Create(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + repo := mock_tag.NewMockRepository(ctrl) + repo.EXPECT().Insert(ctx, masterTx, gomock.Any()).Return(1, nil) + + service := New(repo) + result, err := service.Create(ctx, masterTx, "sampleTag") + + assert.NoError(t, err) + assert.NotNil(t, result) +} + +func TestService_Delete(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + repo := mock_tag.NewMockRepository(ctrl) + repo.EXPECT().UpDeleteFlag(ctx, masterTx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + repo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyTag, nil) + + service := New(repo) + result, err := service.Delete(ctx, masterTx, dummyTag.ID) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.NotNil(t, result.DeletedAt) +} + +func TestService_GetByID(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + repo := mock_tag.NewMockRepository(ctrl) + repo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyTag, nil) + + service := New(repo) + result, err := service.GetByID(ctx, masterTx, dummyTag.ID) + + assert.NoError(t, err) + assert.NotNil(t, result) +} + +func TestService_GetByWishCardID(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + repo := mock_tag.NewMockRepository(ctrl) + repo.EXPECT().SelectByWishCardID(ctx, masterTx, 1).Return(dummyTagSlice, nil) + + service := New(repo) + result, err := service.GetByWishCardID(ctx, masterTx, 1) + + assert.NoError(t, err) + assert.NotNil(t, result) +} + +func TestService_GetByMemoryID(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + repo := mock_tag.NewMockRepository(ctrl) + repo.EXPECT().SelectByMemoryID(ctx, masterTx, 1).Return(dummyTagSlice, nil) + + service := New(repo) + result, err := service.GetByMemoryID(ctx, masterTx, 1) + + assert.NoError(t, err) + assert.NotNil(t, result) +} diff --git a/pkg/domain/service/wishcard/mock_wish_card/mock_service.go b/pkg/domain/service/wishcard/mock_wish_card/mock_service.go new file mode 100644 index 0000000..8b685ed --- /dev/null +++ b/pkg/domain/service/wishcard/mock_wish_card/mock_service.go @@ -0,0 +1,306 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: pkg/domain/service/wishcard/service.go + +// Package mock_wish_card is a generated GoMock package. +package mock_wish_card + +import ( + context "context" + gomock "github.com/golang/mock/gomock" + reflect "reflect" + time "time" + wishcard "wantum/pkg/domain/entity/wishcard" + repository "wantum/pkg/domain/repository" +) + +// MockService is a mock of Service interface +type MockService struct { + ctrl *gomock.Controller + recorder *MockServiceMockRecorder +} + +// MockServiceMockRecorder is the mock recorder for MockService +type MockServiceMockRecorder struct { + mock *MockService +} + +// NewMockService creates a new mock instance +func NewMockService(ctrl *gomock.Controller) *MockService { + mock := &MockService{ctrl: ctrl} + mock.recorder = &MockServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockService) EXPECT() *MockServiceMockRecorder { + return m.recorder +} + +// Create mocks base method +func (m *MockService) Create(ctx context.Context, masterTx repository.MasterTx, activity, description string, date *time.Time, userID, categoryID, placeID int, tagsIDs []int) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Create", ctx, masterTx, activity, description, date, userID, categoryID, placeID, tagsIDs) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Create indicates an expected call of Create +func (mr *MockServiceMockRecorder) Create(ctx, masterTx, activity, description, date, userID, categoryID, placeID, tagsIDs interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockService)(nil).Create), ctx, masterTx, activity, description, date, userID, categoryID, placeID, tagsIDs) +} + +// Update mocks base method +func (m *MockService) Update(ctx context.Context, masterTx repository.MasterTx, wishCardID int, activity, description string, date, doneAt *time.Time, userID, placeID int) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Update", ctx, masterTx, wishCardID, activity, description, date, doneAt, userID, placeID) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Update indicates an expected call of Update +func (mr *MockServiceMockRecorder) Update(ctx, masterTx, wishCardID, activity, description, date, doneAt, userID, placeID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockService)(nil).Update), ctx, masterTx, wishCardID, activity, description, date, doneAt, userID, placeID) +} + +// UpdateActivity mocks base method +func (m *MockService) UpdateActivity(ctx context.Context, masterTx repository.MasterTx, wishCardID int, activity string) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateActivity", ctx, masterTx, wishCardID, activity) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateActivity indicates an expected call of UpdateActivity +func (mr *MockServiceMockRecorder) UpdateActivity(ctx, masterTx, wishCardID, activity interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateActivity", reflect.TypeOf((*MockService)(nil).UpdateActivity), ctx, masterTx, wishCardID, activity) +} + +// UpdateDescription mocks base method +func (m *MockService) UpdateDescription(ctx context.Context, masterTx repository.MasterTx, wishCardID int, description string) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateDescription", ctx, masterTx, wishCardID, description) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateDescription indicates an expected call of UpdateDescription +func (mr *MockServiceMockRecorder) UpdateDescription(ctx, masterTx, wishCardID, description interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateDescription", reflect.TypeOf((*MockService)(nil).UpdateDescription), ctx, masterTx, wishCardID, description) +} + +// UpdateDate mocks base method +func (m *MockService) UpdateDate(ctx context.Context, masterTx repository.MasterTx, wishCardID int, date *time.Time) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateDate", ctx, masterTx, wishCardID, date) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateDate indicates an expected call of UpdateDate +func (mr *MockServiceMockRecorder) UpdateDate(ctx, masterTx, wishCardID, date interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateDate", reflect.TypeOf((*MockService)(nil).UpdateDate), ctx, masterTx, wishCardID, date) +} + +// UpdateDoneAt mocks base method +func (m *MockService) UpdateDoneAt(ctx context.Context, masterTx repository.MasterTx, wishCardID int, doneAt *time.Time) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateDoneAt", ctx, masterTx, wishCardID, doneAt) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateDoneAt indicates an expected call of UpdateDoneAt +func (mr *MockServiceMockRecorder) UpdateDoneAt(ctx, masterTx, wishCardID, doneAt interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateDoneAt", reflect.TypeOf((*MockService)(nil).UpdateDoneAt), ctx, masterTx, wishCardID, doneAt) +} + +// UpdateAuthor mocks base method +func (m *MockService) UpdateAuthor(ctx context.Context, masterTx repository.MasterTx, wishCardID, userID int) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateAuthor", ctx, masterTx, wishCardID, userID) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateAuthor indicates an expected call of UpdateAuthor +func (mr *MockServiceMockRecorder) UpdateAuthor(ctx, masterTx, wishCardID, userID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAuthor", reflect.TypeOf((*MockService)(nil).UpdateAuthor), ctx, masterTx, wishCardID, userID) +} + +// UpdatePlace mocks base method +func (m *MockService) UpdatePlace(ctx context.Context, masterTx repository.MasterTx, wishCardID, placeID int) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdatePlace", ctx, masterTx, wishCardID, placeID) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdatePlace indicates an expected call of UpdatePlace +func (mr *MockServiceMockRecorder) UpdatePlace(ctx, masterTx, wishCardID, placeID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdatePlace", reflect.TypeOf((*MockService)(nil).UpdatePlace), ctx, masterTx, wishCardID, placeID) +} + +// UpdateCategory mocks base method +func (m *MockService) UpdateCategory(ctx context.Context, masterTx repository.MasterTx, wishCardID, categoryID int) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateCategory", ctx, masterTx, wishCardID, categoryID) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateCategory indicates an expected call of UpdateCategory +func (mr *MockServiceMockRecorder) UpdateCategory(ctx, masterTx, wishCardID, categoryID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateCategory", reflect.TypeOf((*MockService)(nil).UpdateCategory), ctx, masterTx, wishCardID, categoryID) +} + +// UpdateWithCategoryID mocks base method +func (m *MockService) UpdateWithCategoryID(ctx context.Context, masterTx repository.MasterTx, wishCardID int, activity, description string, date, doneAt *time.Time, userID, categoryID, placeID int, tagIDs []int) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateWithCategoryID", ctx, masterTx, wishCardID, activity, description, date, doneAt, userID, categoryID, placeID, tagIDs) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpdateWithCategoryID indicates an expected call of UpdateWithCategoryID +func (mr *MockServiceMockRecorder) UpdateWithCategoryID(ctx, masterTx, wishCardID, activity, description, date, doneAt, userID, categoryID, placeID, tagIDs interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateWithCategoryID", reflect.TypeOf((*MockService)(nil).UpdateWithCategoryID), ctx, masterTx, wishCardID, activity, description, date, doneAt, userID, categoryID, placeID, tagIDs) +} + +// Delete mocks base method +func (m *MockService) Delete(ctx context.Context, masterTx repository.MasterTx, wishCardID int) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Delete", ctx, masterTx, wishCardID) + ret0, _ := ret[0].(error) + return ret0 +} + +// Delete indicates an expected call of Delete +func (mr *MockServiceMockRecorder) Delete(ctx, masterTx, wishCardID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockService)(nil).Delete), ctx, masterTx, wishCardID) +} + +// UpDeleteFlag mocks base method +func (m *MockService) UpDeleteFlag(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpDeleteFlag", ctx, masterTx, wishCardID) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// UpDeleteFlag indicates an expected call of UpDeleteFlag +func (mr *MockServiceMockRecorder) UpDeleteFlag(ctx, masterTx, wishCardID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpDeleteFlag", reflect.TypeOf((*MockService)(nil).UpDeleteFlag), ctx, masterTx, wishCardID) +} + +// DownDeleteFlag mocks base method +func (m *MockService) DownDeleteFlag(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DownDeleteFlag", ctx, masterTx, wishCardID) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DownDeleteFlag indicates an expected call of DownDeleteFlag +func (mr *MockServiceMockRecorder) DownDeleteFlag(ctx, masterTx, wishCardID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DownDeleteFlag", reflect.TypeOf((*MockService)(nil).DownDeleteFlag), ctx, masterTx, wishCardID) +} + +// GetByID mocks base method +func (m *MockService) GetByID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetByID", ctx, masterTx, wishCardID) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetByID indicates an expected call of GetByID +func (mr *MockServiceMockRecorder) GetByID(ctx, masterTx, wishCardID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByID", reflect.TypeOf((*MockService)(nil).GetByID), ctx, masterTx, wishCardID) +} + +// GetByIDs mocks base method +func (m *MockService) GetByIDs(ctx context.Context, masterTx repository.MasterTx, wishCardIDs []int) (wishcard.EntitySlice, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetByIDs", ctx, masterTx, wishCardIDs) + ret0, _ := ret[0].(wishcard.EntitySlice) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetByIDs indicates an expected call of GetByIDs +func (mr *MockServiceMockRecorder) GetByIDs(ctx, masterTx, wishCardIDs interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByIDs", reflect.TypeOf((*MockService)(nil).GetByIDs), ctx, masterTx, wishCardIDs) +} + +// GetByCategoryID mocks base method +func (m *MockService) GetByCategoryID(ctx context.Context, masterTx repository.MasterTx, categoryID int) (wishcard.EntitySlice, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetByCategoryID", ctx, masterTx, categoryID) + ret0, _ := ret[0].(wishcard.EntitySlice) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetByCategoryID indicates an expected call of GetByCategoryID +func (mr *MockServiceMockRecorder) GetByCategoryID(ctx, masterTx, categoryID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetByCategoryID", reflect.TypeOf((*MockService)(nil).GetByCategoryID), ctx, masterTx, categoryID) +} + +// AddTags mocks base method +func (m *MockService) AddTags(ctx context.Context, masterTx repository.MasterTx, wishCardID int, tagIDs []int) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "AddTags", ctx, masterTx, wishCardID, tagIDs) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// AddTags indicates an expected call of AddTags +func (mr *MockServiceMockRecorder) AddTags(ctx, masterTx, wishCardID, tagIDs interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddTags", reflect.TypeOf((*MockService)(nil).AddTags), ctx, masterTx, wishCardID, tagIDs) +} + +// DeleteTags mocks base method +func (m *MockService) DeleteTags(ctx context.Context, masterTx repository.MasterTx, wishCardID int, tagIDs []int) (*wishcard.Entity, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteTags", ctx, masterTx, wishCardID, tagIDs) + ret0, _ := ret[0].(*wishcard.Entity) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DeleteTags indicates an expected call of DeleteTags +func (mr *MockServiceMockRecorder) DeleteTags(ctx, masterTx, wishCardID, tagIDs interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteTags", reflect.TypeOf((*MockService)(nil).DeleteTags), ctx, masterTx, wishCardID, tagIDs) +} diff --git a/pkg/domain/service/wishcard/service.go b/pkg/domain/service/wishcard/service.go new file mode 100644 index 0000000..9b9ba49 --- /dev/null +++ b/pkg/domain/service/wishcard/service.go @@ -0,0 +1,345 @@ +package wishcard + +import ( + "context" + "fmt" + "net/http" + "time" + wishCardEntity "wantum/pkg/domain/entity/wishcard" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/repository/wishcard" + "wantum/pkg/domain/repository/wishcardtag" + "wantum/pkg/werrors" + + "google.golang.org/grpc/codes" +) + +type Service interface { + Create(ctx context.Context, masterTx repository.MasterTx, activity, description string, date *time.Time, userID, categoryID, placeID int, tagsIDs []int) (*wishCardEntity.Entity, error) + Update(ctx context.Context, masterTx repository.MasterTx, wishCardID int, activity, description string, date, doneAt *time.Time, userID, placeID int) (*wishCardEntity.Entity, error) + UpdateActivity(ctx context.Context, masterTx repository.MasterTx, wishCardID int, activity string) (*wishCardEntity.Entity, error) + UpdateDescription(ctx context.Context, masterTx repository.MasterTx, wishCardID int, description string) (*wishCardEntity.Entity, error) + UpdateDate(ctx context.Context, masterTx repository.MasterTx, wishCardID int, date *time.Time) (*wishCardEntity.Entity, error) + UpdateDoneAt(ctx context.Context, masterTx repository.MasterTx, wishCardID int, doneAt *time.Time) (*wishCardEntity.Entity, error) + UpdateAuthor(ctx context.Context, masterTx repository.MasterTx, wishCardID, userID int) (*wishCardEntity.Entity, error) + UpdatePlace(ctx context.Context, masterTx repository.MasterTx, wishCardID, placeID int) (*wishCardEntity.Entity, error) + UpdateCategory(ctx context.Context, masterTx repository.MasterTx, wishCardID, categoryID int) (*wishCardEntity.Entity, error) + UpdateWithCategoryID(ctx context.Context, masterTx repository.MasterTx, wishCardID int, activity, description string, date, doneAt *time.Time, userID, categoryID, placeID int, tagIDs []int) (*wishCardEntity.Entity, error) + Delete(ctx context.Context, masterTx repository.MasterTx, wishCardID int) error + UpDeleteFlag(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (*wishCardEntity.Entity, error) + DownDeleteFlag(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (*wishCardEntity.Entity, error) + GetByID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (*wishCardEntity.Entity, error) + GetByIDs(ctx context.Context, masterTx repository.MasterTx, wishCardIDs []int) (wishCardEntity.EntitySlice, error) + GetByCategoryID(ctx context.Context, masterTx repository.MasterTx, categoryID int) (wishCardEntity.EntitySlice, error) + AddTags(ctx context.Context, masterTx repository.MasterTx, wishCardID int, tagIDs []int) (*wishCardEntity.Entity, error) + DeleteTags(ctx context.Context, masterTx repository.MasterTx, wishCardID int, tagIDs []int) (*wishCardEntity.Entity, error) +} + +type service struct { + wishCardRepository wishcard.Repository + wishCardTagRepository wishcardtag.Repository +} + +func New(wcRepo wishcard.Repository, wctRepo wishcardtag.Repository) Service { + return &service{ + wishCardRepository: wcRepo, + wishCardTagRepository: wctRepo, + } +} + +func (s *service) Create(ctx context.Context, masterTx repository.MasterTx, activity, description string, date *time.Time, userID, categoryID, placeID int, tagIDs []int) (*wishCardEntity.Entity, error) { + + now := time.Now() + wishCard := &wishCardEntity.Entity{ + Activity: activity, + Description: description, + Date: date, + CreatedAt: &now, + UpdatedAt: &now, + } + newID, err := s.wishCardRepository.Insert(ctx, masterTx, wishCard, categoryID) + if err != nil { + return nil, werrors.Stack(err) + } + wishCard.ID = newID + + // create relation + if err = s.wishCardTagRepository.BulkInsert(ctx, masterTx, newID, tagIDs); err != nil { + return nil, werrors.Stack(err) + } + + return wishCard, nil +} + +func (s *service) Update(ctx context.Context, masterTx repository.MasterTx, wishCardID int, activity, description string, date, doneAt *time.Time, userID, placeID int) (*wishCardEntity.Entity, error) { + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + + now := time.Now() + wishCard.Author.ID = userID // NOTE: 今後、authorの更新があるかも + wishCard.Activity = activity + wishCard.Description = description + wishCard.Date = date + wishCard.DoneAt = doneAt + wishCard.UpdatedAt = &now + wishCard.Place.ID = placeID + // wishCard.Tags = tags // TODO: 消す + + if err = s.wishCardRepository.Update(ctx, masterTx, wishCard); err != nil { + return nil, werrors.Stack(err) + } + + return wishCard, nil +} + +func (s *service) UpdateActivity(ctx context.Context, masterTx repository.MasterTx, wishCardID int, activity string) (*wishCardEntity.Entity, error) { + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + if wishCard == nil { + return nil, werrors.Stack(werrors.WishCardNotFound) + } + now := time.Now() + wishCard.UpdatedAt = &now + wishCard.Activity = activity + if err := s.wishCardRepository.UpdateActivity(ctx, masterTx, wishCardID, wishCard.Activity, wishCard.UpdatedAt); err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (s *service) UpdateDescription(ctx context.Context, masterTx repository.MasterTx, wishCardID int, description string) (*wishCardEntity.Entity, error) { + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + if wishCard == nil { + return nil, werrors.Stack(werrors.WishCardNotFound) + } + now := time.Now() + wishCard.UpdatedAt = &now + wishCard.Description = description + if err := s.wishCardRepository.UpdateDescription(ctx, masterTx, wishCardID, wishCard.Description, wishCard.UpdatedAt); err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (s *service) UpdateDate(ctx context.Context, masterTx repository.MasterTx, wishCardID int, date *time.Time) (*wishCardEntity.Entity, error) { + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + if wishCard == nil { + return nil, werrors.Stack(werrors.WishCardNotFound) + } + now := time.Now() + wishCard.UpdatedAt = &now + wishCard.Date = date + if err := s.wishCardRepository.UpdateDate(ctx, masterTx, wishCardID, wishCard.Date, wishCard.UpdatedAt); err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (s *service) UpdateDoneAt(ctx context.Context, masterTx repository.MasterTx, wishCardID int, doneAt *time.Time) (*wishCardEntity.Entity, error) { + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + if wishCard == nil { + return nil, werrors.Stack(werrors.WishCardNotFound) + } + now := time.Now() + wishCard.UpdatedAt = &now + wishCard.DoneAt = doneAt + if err := s.wishCardRepository.UpdateDoneAt(ctx, masterTx, wishCardID, wishCard.DoneAt, wishCard.UpdatedAt); err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (s *service) UpdateAuthor(ctx context.Context, masterTx repository.MasterTx, wishCardID, userID int) (*wishCardEntity.Entity, error) { + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + if wishCard == nil { + return nil, werrors.Stack(werrors.WishCardNotFound) + } + now := time.Now() + wishCard.UpdatedAt = &now + wishCard.Author.ID = userID + if err := s.wishCardRepository.UpdateUserID(ctx, masterTx, wishCardID, wishCard.Author.ID, wishCard.UpdatedAt); err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (s *service) UpdatePlace(ctx context.Context, masterTx repository.MasterTx, wishCardID, placeID int) (*wishCardEntity.Entity, error) { + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + if wishCard == nil { + return nil, werrors.Stack(werrors.WishCardNotFound) + } + now := time.Now() + wishCard.UpdatedAt = &now + wishCard.Place.ID = placeID + if err := s.wishCardRepository.UpdatePlaceID(ctx, masterTx, wishCardID, wishCard.Place.ID, wishCard.UpdatedAt); err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (s *service) UpdateCategory(ctx context.Context, masterTx repository.MasterTx, wishCardID, categoryID int) (*wishCardEntity.Entity, error) { + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + if wishCard == nil { + return nil, werrors.Stack(werrors.WishCardNotFound) + } + now := time.Now() + wishCard.UpdatedAt = &now + if err := s.wishCardRepository.UpdateCategoryID(ctx, masterTx, wishCardID, categoryID, wishCard.UpdatedAt); err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +// WARNING: 空値があった時、元データが消滅する。 +func (s *service) UpdateWithCategoryID(ctx context.Context, masterTx repository.MasterTx, wishCardID int, activity, description string, date, doneAt *time.Time, userID, categoryID, placeID int, tagIDs []int) (*wishCardEntity.Entity, error) { + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + + now := time.Now() + wishCard.Author.ID = userID // NOTE: 今後、authorの更新があるかも + wishCard.Activity = activity + wishCard.Description = description + wishCard.Date = date + wishCard.DoneAt = doneAt + wishCard.Place.ID = placeID + wishCard.UpdatedAt = &now + // wishCard.Tags = tags // TODO: 消す + + if err = s.wishCardRepository.UpdateWithCategoryID(ctx, masterTx, wishCard, categoryID); err != nil { + return nil, werrors.Stack(err) + } + + // regist tag + if err = s.wishCardTagRepository.DeleteByWishCardID(ctx, masterTx, wishCardID); err != nil { + return nil, werrors.Stack(err) + } + if err = s.wishCardTagRepository.BulkInsert(ctx, masterTx, wishCardID, tagIDs); err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (s *service) UpDeleteFlag(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (*wishCardEntity.Entity, error) { + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + now := time.Now() + wishCard.UpdatedAt = &now + wishCard.DeletedAt = &now + + if err = s.wishCardRepository.UpDeleteFlag(ctx, masterTx, wishCard.ID, wishCard.UpdatedAt, wishCard.DeletedAt); err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (s *service) DownDeleteFlag(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (*wishCardEntity.Entity, error) { + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + + now := time.Now() + wishCard.UpdatedAt = &now + wishCard.DeletedAt = nil + if err = s.wishCardRepository.DownDeleteFlag(ctx, masterTx, wishCard.ID, wishCard.UpdatedAt); err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (s *service) Delete(ctx context.Context, masterTx repository.MasterTx, wishCardID int) error { + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return werrors.Stack(err) + } + if wishCard.DeletedAt == nil { + return werrors.Newf( + fmt.Errorf("can't delete this data. this data did not up a delete flag. wishCardID=%v", wishCardID), + codes.FailedPrecondition, + http.StatusBadRequest, + "このデータは削除できません", + "could not delete this place", + ) + } + if err = s.wishCardRepository.Delete(ctx, masterTx, wishCard); err != nil { + return werrors.Stack(err) + } + if err = s.wishCardTagRepository.DeleteByWishCardID(ctx, masterTx, wishCardID); err != nil { + return werrors.Stack(err) + } + return nil +} + +func (s *service) GetByID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (*wishCardEntity.Entity, error) { + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (s *service) GetByIDs(ctx context.Context, masterTx repository.MasterTx, wishCardIDs []int) (wishCardEntity.EntitySlice, error) { + wishCards, err := s.wishCardRepository.SelectByIDs(ctx, masterTx, wishCardIDs) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCards, nil +} + +func (s *service) GetByCategoryID(ctx context.Context, masterTx repository.MasterTx, categoryID int) (wishCardEntity.EntitySlice, error) { + wishCards, err := s.wishCardRepository.SelectByCategoryID(ctx, masterTx, categoryID) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCards, nil +} + +func (s *service) AddTags(ctx context.Context, masterTx repository.MasterTx, wishCardID int, tagIDs []int) (*wishCardEntity.Entity, error) { + if err := s.wishCardTagRepository.BulkInsert(ctx, masterTx, wishCardID, tagIDs); err != nil { + return nil, err + } + + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} + +func (s *service) DeleteTags(ctx context.Context, masterTx repository.MasterTx, wishCardID int, tagIDs []int) (*wishCardEntity.Entity, error) { + if err := s.wishCardTagRepository.DeleteByIDs(ctx, masterTx, wishCardID, tagIDs); err != nil { + return nil, werrors.Stack(err) + } + + wishCard, err := s.wishCardRepository.SelectByID(ctx, masterTx, wishCardID) + if err != nil { + return nil, werrors.Stack(err) + } + return wishCard, nil +} diff --git a/pkg/domain/service/wishcard/service_test.go b/pkg/domain/service/wishcard/service_test.go new file mode 100644 index 0000000..fb4567e --- /dev/null +++ b/pkg/domain/service/wishcard/service_test.go @@ -0,0 +1,858 @@ +package wishcard + +import ( + "context" + "os" + "testing" + "time" + placeEntity "wantum/pkg/domain/entity/place" + userEntity "wantum/pkg/domain/entity/user" + wishCardEntity "wantum/pkg/domain/entity/wishcard" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/repository/wishcard/mock_wish_card" + "wantum/pkg/domain/repository/wishcardtag/mock_wish_card_tag" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/assert" +) + +var ( + masterTx repository.MasterTx + + dummyDate = time.Date(2020, 9, 1, 12, 0, 0, 0, time.Local) + dummyActivity = "sampleActivity" + dummyDescription = "sampleDescription" + dummyWishCardID = 2 + dummyUserID = 1 + dummyPlaceID = 1 + dummyCategoryID = 1 +) + +func TestMain(m *testing.M) { + before() + code := m.Run() + os.Exit(code) +} + +func before() { + masterTx = repository.NewMockMasterTx() +} + +func TestService_Create(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().Insert(ctx, masterTx, gomock.Any(), gomock.Any()).Return(1, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + wctRepo.EXPECT().BulkInsert(ctx, masterTx, gomock.Any(), gomock.Any()).Return(nil) + + service := New(wcRepo, wctRepo) + result, err := service.Create(ctx, masterTx, dummyActivity, dummyDescription, &dummyDate, 1, 1, 1, []int{1, 2}) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, 1, result.ID) +} + +func TestService_Update(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: "act", + Description: "desc", + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + wcRepo.EXPECT().Update(ctx, masterTx, gomock.Any()).Return(nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + result, err := service.Update(ctx, masterTx, 1, dummyActivity, dummyDescription, &dummyDate, &dummyDate, 1, 1) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyActivity, result.Activity) + assert.Equal(t, dummyDescription, result.Description) +} + +func TestService_UpdateActivity(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: "act", + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().UpdateActivity(ctx, masterTx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + result, err := service.UpdateActivity(ctx, masterTx, dummyWishCardID, dummyActivity) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyActivity, result.Activity) + assert.NotEqual(t, dummyDate, result.UpdatedAt) + }) + + t.Run("failure_存在しないデータ", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(nil, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + _, err := service.UpdateActivity(ctx, masterTx, dummyWishCardID, dummyActivity) + + assert.Error(t, err) + }) +} + +func TestService_UpdateDescription(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: "desc", + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().UpdateDescription(ctx, masterTx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + result, err := service.UpdateDescription(ctx, masterTx, dummyWishCardID, dummyDescription) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyDescription, result.Description) + assert.NotEqual(t, dummyDate, result.UpdatedAt) + }) + + t.Run("failure_存在しないデータ", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(nil, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + _, err := service.UpdateDescription(ctx, masterTx, dummyWishCardID, dummyDescription) + + assert.Error(t, err) + }) +} + +func TestService_UpdateDate(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + _dummyDate := time.Date(2020, 10, 10, 10, 0, 0, 0, time.Local) + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &_dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().UpdateDate(ctx, masterTx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + result, err := service.UpdateDate(ctx, masterTx, dummyWishCardID, &dummyDate) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyDate, result.Date.Local()) + assert.NotEqual(t, dummyDate, result.UpdatedAt) + }) + + t.Run("failure_存在しないデータ", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(nil, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + _, err := service.UpdateDate(ctx, masterTx, dummyWishCardID, &dummyDate) + + assert.Error(t, err) + }) +} + +func TestService_UpdateDoneAt(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + _dummyDate := time.Date(2020, 10, 10, 10, 0, 0, 0, time.Local) + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &_dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().UpdateDoneAt(ctx, masterTx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + result, err := service.UpdateDoneAt(ctx, masterTx, dummyWishCardID, &dummyDate) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyDate, result.DoneAt.Local()) + assert.NotEqual(t, dummyDate, result.UpdatedAt) + }) + + t.Run("failure_存在しないデータ", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(nil, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + _, err := service.UpdateDoneAt(ctx, masterTx, dummyWishCardID, &dummyDate) + + assert.Error(t, err) + }) + +} + +func TestService_UpdateAuthor(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 5, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().UpdateUserID(ctx, masterTx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + result, err := service.UpdateAuthor(ctx, masterTx, dummyWishCardID, dummyUserID) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyUserID, result.Author.ID) + assert.NotEqual(t, dummyDate, result.UpdatedAt) + }) + + t.Run("failure_存在しないデータ", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(nil, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + _, err := service.UpdateAuthor(ctx, masterTx, dummyWishCardID, dummyUserID) + + assert.Error(t, err) + }) +} + +func TestService_UpdatePlace(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 5, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().UpdatePlaceID(ctx, masterTx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + result, err := service.UpdatePlace(ctx, masterTx, dummyWishCardID, dummyPlaceID) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyPlaceID, result.Place.ID) + assert.NotEqual(t, dummyDate, result.UpdatedAt) + }) + + t.Run("failure_存在しないデータ", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(nil, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + _, err := service.UpdatePlace(ctx, masterTx, dummyWishCardID, dummyPlaceID) + + assert.Error(t, err) + }) + +} + +func TestService_UpdateCategory(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().UpdateCategoryID(ctx, masterTx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + result, err := service.UpdateCategory(ctx, masterTx, dummyWishCardID, dummyCategoryID) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.NotEqual(t, dummyDate, result.UpdatedAt) + }) + + t.Run("failure_存在しないデータ", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(nil, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + _, err := service.UpdateCategory(ctx, masterTx, dummyWishCardID, dummyCategoryID) + + assert.Error(t, err) + }) +} + +func TestService_UpdateWithCategoryID(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: "act", + Description: "desc", + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + wcRepo.EXPECT().UpdateWithCategoryID(ctx, masterTx, gomock.Any(), gomock.Any()).Return(nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + wctRepo.EXPECT().BulkInsert(ctx, masterTx, gomock.Any(), gomock.Any()).Return(nil) + wctRepo.EXPECT().DeleteByWishCardID(ctx, masterTx, gomock.Any()).Return(nil) + + service := New(wcRepo, wctRepo) + result, err := service.UpdateWithCategoryID(ctx, masterTx, 1, dummyActivity, dummyDescription, &dummyDate, &dummyDate, 1, 1, 1, []int{1, 2}) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyActivity, result.Activity) + assert.Equal(t, dummyDescription, result.Description) +} + +func TestService_UpDeleteFlag(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + wcRepo.EXPECT().UpDeleteFlag(ctx, masterTx, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + result, err := service.UpDeleteFlag(ctx, masterTx, 1) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.NotNil(t, result.DeletedAt) +} + +func TestService_DownDeleteFlag(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + wcRepo.EXPECT().DownDeleteFlag(ctx, masterTx, gomock.Any(), gomock.Any()).Return(nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + result, err := service.DownDeleteFlag(ctx, masterTx, 1) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Nil(t, result.DeletedAt) +} + +func TestService_Delete(t *testing.T) { + t.Run("success", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + wcRepo.EXPECT().Delete(ctx, masterTx, gomock.Any()).Return(nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + wctRepo.EXPECT().DeleteByWishCardID(ctx, masterTx, gomock.Any()).Return(nil) + + service := New(wcRepo, wctRepo) + err := service.Delete(ctx, masterTx, 1) + + assert.NoError(t, err) + + }) + + t.Run("failure_deleteフラグがたってない", func(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + err := service.Delete(ctx, masterTx, 1) + + assert.Error(t, err) + }) +} + +func TestService_GetByID(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + result, err := service.GetByID(ctx, masterTx, 1) + + assert.NoError(t, err) + assert.NotNil(t, result) +} + +func TestService_GetByIDs(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := wishCardEntity.EntitySlice{ + &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + }, + &wishCardEntity.Entity{ + ID: 2, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByIDs(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + result, err := service.GetByIDs(ctx, masterTx, []int{1, 2}) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, 2, len(result)) +} + +func TestService_GetByCategoryID(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := wishCardEntity.EntitySlice{ + &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + }, + &wishCardEntity.Entity{ + ID: 2, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByCategoryID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + + service := New(wcRepo, wctRepo) + result, err := service.GetByCategoryID(ctx, masterTx, 1) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, 2, len(result)) +} + +func TestService_AddTags(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + wctRepo.EXPECT().BulkInsert(ctx, masterTx, gomock.Any(), gomock.Any()).Return(nil) + + service := New(wcRepo, wctRepo) + result, err := service.AddTags(ctx, masterTx, 1, []int{1, 2}) + + assert.NoError(t, err) + assert.NotNil(t, result) +} + +func TestService_DeleteTags(t *testing.T) { + ctx := context.Background() + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + dummyData := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + + wcRepo := mock_wish_card.NewMockRepository(ctrl) + wcRepo.EXPECT().SelectByID(ctx, masterTx, gomock.Any()).Return(dummyData, nil) + + wctRepo := mock_wish_card_tag.NewMockRepository(ctrl) + wctRepo.EXPECT().DeleteByIDs(ctx, masterTx, gomock.Any(), gomock.Any()).Return(nil) + + service := New(wcRepo, wctRepo) + result, err := service.DeleteTags(ctx, masterTx, 1, []int{1, 2}) + + assert.NoError(t, err) + assert.NotNil(t, result) +} diff --git a/pkg/infrastructure/mysql/place/repository.go b/pkg/infrastructure/mysql/place/repository.go new file mode 100644 index 0000000..b7992e3 --- /dev/null +++ b/pkg/infrastructure/mysql/place/repository.go @@ -0,0 +1,234 @@ +package place + +import ( + "context" + "database/sql" + "errors" + "time" + placeEntity "wantum/pkg/domain/entity/place" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/repository/place" + "wantum/pkg/infrastructure/mysql" + "wantum/pkg/tlog" + "wantum/pkg/werrors" + + "google.golang.org/grpc/codes" +) + +type placeRepositoryImplement struct { + masterTxManager repository.MasterTxManager +} + +func New(txManager repository.MasterTxManager) place.Repository { + return &placeRepositoryImplement{ + masterTxManager: txManager, + } +} + +func (repo *placeRepositoryImplement) Insert(ctx context.Context, masterTx repository.MasterTx, place *placeEntity.Entity) (int, error) { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return 0, werrors.FromConstant(err, werrors.ServerError) + } + result, err := tx.Exec(` + INSERT INTO places( + name, created_at, updated_at + ) VALUES (?, ?, ?) + `, place.Name, + place.CreatedAt, + place.UpdatedAt, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return 0, werrors.FromConstant(err, werrors.ServerError) + } + + id, err := result.LastInsertId() + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return 0, werrors.FromConstant(err, werrors.ServerError) + } + return int(id), nil +} + +func (repo *placeRepositoryImplement) Update(ctx context.Context, masterTx repository.MasterTx, place *placeEntity.Entity) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE places + SET name=?, updated_at=? + WHERE id=? + `, place.Name, + place.UpdatedAt, + place.ID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *placeRepositoryImplement) UpdateName(ctx context.Context, masterTx repository.MasterTx, placeID int, name string, updatedAt *time.Time) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE places + SET name=?, updated_at=? + WHERE id=? + `, name, + updatedAt, + placeID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *placeRepositoryImplement) UpDeleteFlag(ctx context.Context, masterTx repository.MasterTx, placeID int, updatedAt, deletedAt *time.Time) error { + if deletedAt == nil { + return werrors.Newf( + errors.New("can't up delete flag. deletedAt is nil"), + codes.Internal, + werrors.ServerError.ErrorCode, + werrors.ServerError.ErrorMessageJP, + werrors.ServerError.ErrorMessageEN, + ) + } + + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE places + SET updated_at=?, deleted_at=? + WHERE id=? + `, updatedAt, + deletedAt, + placeID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *placeRepositoryImplement) DownDeleteFlag(ctx context.Context, masterTx repository.MasterTx, placeID int, updatedAt *time.Time) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE places + SET updated_at=?, deleted_at=? + WHERE id=? + `, updatedAt, + nil, + placeID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *placeRepositoryImplement) Delete(ctx context.Context, masterTx repository.MasterTx, place *placeEntity.Entity) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + DELETE FROM places + WHERE id=? and deleted_at is not null + `, place.ID) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *placeRepositoryImplement) SelectByID(ctx context.Context, masterTx repository.MasterTx, placeID int) (*placeEntity.Entity, error) { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + row := tx.QueryRow(` + SELECT id, name, created_at, updated_at, deleted_at + FROM places + WHERE id=? + `, placeID) + result, err := convertToPlaceEntity(row) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + return result, nil +} + +func (repo *placeRepositoryImplement) SelectAll(ctx context.Context, masterTx repository.MasterTx) (placeEntity.EntitySlice, error) { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + rows, err := tx.Query(` + SELECT id, name, created_at, updated_at, deleted_at + FROM places + `) + if err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + result, err := convertToPlaceEntitySlice(rows) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + return result, nil +} + +func convertToPlaceEntity(row *sql.Row) (*placeEntity.Entity, error) { + var place placeEntity.Entity + if err := row.Scan(&place.ID, &place.Name, &place.CreatedAt, &place.UpdatedAt, &place.DeletedAt); err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + return nil, werrors.FromConstant(err, werrors.ServerError) + } + return &place, nil +} + +func convertToPlaceEntitySlice(rows *sql.Rows) (placeEntity.EntitySlice, error) { + var places placeEntity.EntitySlice + for rows.Next() { + var place placeEntity.Entity + if err := rows.Scan(&place.ID, &place.Name, &place.CreatedAt, &place.UpdatedAt, &place.DeletedAt); err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + return nil, werrors.FromConstant(err, werrors.ServerError) + } + places = append(places, &place) + } + return places, nil +} diff --git a/pkg/infrastructure/mysql/place/repository_test.go b/pkg/infrastructure/mysql/place/repository_test.go new file mode 100644 index 0000000..c7c85ea --- /dev/null +++ b/pkg/infrastructure/mysql/place/repository_test.go @@ -0,0 +1,270 @@ +package place + +import ( + "context" + "database/sql" + "errors" + "log" + "os" + "testing" + "time" + placeEntity "wantum/pkg/domain/entity/place" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/repository/place" + tx "wantum/pkg/infrastructure/mysql" + "wantum/pkg/testutil" + + "github.com/stretchr/testify/assert" + + _ "github.com/go-sql-driver/mysql" +) + +var ( + db *sql.DB + txManager repository.MasterTxManager + repo place.Repository + dummyDate time.Time + dummyPlace = "samplePlace" +) + +func TestMain(m *testing.M) { + before() + code := m.Run() + after() + os.Exit(code) +} + +// repositoryを作ってもらう +func before() { + var err error + db, err = testutil.ConnectLocalDB() + if err != nil { + log.Fatal("faild to connect db: ", err) + } + txManager = tx.NewDBMasterTxManager(db) + repo = New(txManager) + dummyDate = time.Date(2020, 9, 1, 12, 0, 0, 0, time.Local) +} + +// dbのコネクションを閉じる +func after() { + db.Close() +} + +func TestInsert(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + place := &placeEntity.Entity{ + Name: dummyPlace, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + var result int + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + result, err = repo.Insert(ctx, masterTx, place) + return err + }) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) +} + +func TestUpdate(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + place := &placeEntity.Entity{ + ID: 1, + Name: dummyPlace, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + var result *placeEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = repo.Update(ctx, masterTx, place); err != nil { + return err + } + + result, err = repo.SelectByID(ctx, masterTx, 1) + return err + }) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyPlace, result.Name) + }) +} + +func TestUpdateName(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + var result *placeEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = repo.UpdateName(ctx, masterTx, 2, dummyPlace, &dummyDate); err != nil { + return err + } + + result, err = repo.SelectByID(ctx, masterTx, 2) + return err + }) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyPlace, result.Name) + }) +} + +func TestUpDeleteFlag(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + _dummyDate := time.Date(2020, 10, 10, 10, 0, 0, 0, time.Local) + place := &placeEntity.Entity{ + Name: dummyPlace, + CreatedAt: &_dummyDate, + UpdatedAt: &_dummyDate, + } + + var result *placeEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + newPlaceID, _ := repo.Insert(ctx, masterTx, place) + + if err = repo.UpDeleteFlag(ctx, masterTx, newPlaceID, &dummyDate, &dummyDate); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, newPlaceID) + return nil + }) + + assert.NoError(t, err) + assert.NotNil(t, result.DeletedAt) + assert.Equal(t, dummyDate, result.UpdatedAt.Local()) + assert.Equal(t, dummyDate, result.DeletedAt.Local()) + }) + + t.Run("failure_deletedAtがnil", func(t *testing.T) { + var err error + ctx := context.Background() + place := &placeEntity.Entity{ + Name: dummyPlace, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + newPlaceID, _ := repo.Insert(ctx, masterTx, place) + + place.ID = newPlaceID + return repo.UpDeleteFlag(ctx, masterTx, newPlaceID, &dummyDate, nil) + }) + + assert.Error(t, err) + }) +} + +func TestDownDeleteFlag(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + place := &placeEntity.Entity{ + Name: dummyPlace, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: &dummyDate, + } + + var result *placeEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + newPlaceID, _ := repo.Insert(ctx, masterTx, place) + + if err = repo.DownDeleteFlag(ctx, masterTx, newPlaceID, &dummyDate); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, newPlaceID) + return nil + }) + + assert.NoError(t, err) + assert.Nil(t, result.DeletedAt) + }) +} + +func TestDelete(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + place := &placeEntity.Entity{ + Name: dummyPlace, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + var result *placeEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + newPlaceID, _ := repo.Insert(ctx, masterTx, place) + place.ID = newPlaceID + repo.UpDeleteFlag(ctx, masterTx, place.ID, &dummyDate, &dummyDate) + + if err = repo.Delete(ctx, masterTx, place); err != nil { + return err + } + + result, err = repo.SelectByID(ctx, masterTx, place.ID) + if result != nil { + return errors.New("削除されたデータが引っかかった") + } + return nil + }) + + assert.NoError(t, err) + assert.Nil(t, result) + }) +} + +func TestSelectByID(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + place := &placeEntity.Entity{ + Name: dummyPlace, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + var result *placeEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + newPlaceID, _ := repo.Insert(ctx, masterTx, place) + + result, err = repo.SelectByID(ctx, masterTx, newPlaceID) + return err + }) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) + +} + +func TestSelectAll(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + var result placeEntity.EntitySlice + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + result, err = repo.SelectAll(ctx, masterTx) + return err + }) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) +} diff --git a/pkg/infrastructure/mysql/tag/repository.go b/pkg/infrastructure/mysql/tag/repository.go new file mode 100644 index 0000000..5e841f0 --- /dev/null +++ b/pkg/infrastructure/mysql/tag/repository.go @@ -0,0 +1,273 @@ +package tag + +import ( + "context" + "database/sql" + "errors" + "strconv" + "strings" + "time" + tagEntity "wantum/pkg/domain/entity/tag" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/repository/tag" + "wantum/pkg/infrastructure/mysql" + "wantum/pkg/tlog" + "wantum/pkg/werrors" + + "google.golang.org/grpc/codes" +) + +type tagRepositoryImplement struct { + masterTxManager repository.MasterTxManager +} + +func New(txManager repository.MasterTxManager) tag.Repository { + return &tagRepositoryImplement{ + masterTxManager: txManager, + } +} + +func (repo *tagRepositoryImplement) Insert(ctx context.Context, masterTx repository.MasterTx, tag *tagEntity.Entity) (int, error) { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return 0, werrors.FromConstant(err, werrors.ServerError) + } + result, err := tx.Exec(` + INSERT INTO tags(name, created_at, updated_at) + VALUES (?,?,?) + `, tag.Name, + tag.CreatedAt, + tag.UpdatedAt, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return 0, werrors.FromConstant(err, werrors.ServerError) + } + id, err := result.LastInsertId() + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return 0, werrors.FromConstant(err, werrors.ServerError) + } + return int(id), nil +} + +func (repo *tagRepositoryImplement) UpDeleteFlag(ctx context.Context, masterTx repository.MasterTx, tagID int, updatedAt, deletedAt *time.Time) error { + if deletedAt == nil { + return werrors.Newf( + errors.New("can't up delete flag. deletedAt is nil"), + codes.Internal, + werrors.ServerError.ErrorCode, + werrors.ServerError.ErrorMessageJP, + werrors.ServerError.ErrorMessageEN, + ) + } + + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE tags + SET updated_at=?, deleted_at=? + WHERE id=? + `, deletedAt, + deletedAt, + tagID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *tagRepositoryImplement) DownDeleteFlag(ctx context.Context, masterTx repository.MasterTx, tagID int, updatedAt *time.Time) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE tags + SET updated_at=?, deleted_at=? + WHERE id=? + `, updatedAt, + nil, + tagID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *tagRepositoryImplement) Delete(ctx context.Context, masterTx repository.MasterTx, tag *tagEntity.Entity) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + DELETE FROM tags + WHERE id=? and deleted_at is not null + `, tag.ID) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *tagRepositoryImplement) SelectByID(ctx context.Context, masterTx repository.MasterTx, tagID int) (*tagEntity.Entity, error) { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + row := tx.QueryRow(` + SELECT id, name, created_at, updated_at, deleted_at + FROM tags + WHERE id=? + `, tagID) + result, err := convertToTagEntity(row) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + return result, nil +} + +func (repo *tagRepositoryImplement) SelectByIDs(ctx context.Context, masterTx repository.MasterTx, tagIDs []int) (tagEntity.EntitySlice, error) { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + + tagIDsStr := make([]string, 0, len(tagIDs)) + for _, id := range tagIDs { + tagIDsStr = append(tagIDsStr, strconv.Itoa(id)) + } + + rows, err := tx.Query(` + SELECT id, name, created_at, updated_at, deleted_at + FROM tags + WHERE id + IN (` + strings.Join(tagIDsStr, ",") + `) + `) + if err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + result, err := convertToTagEntitySlice(rows) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + return result, nil +} + +func (repo *tagRepositoryImplement) SelectByName(ctx context.Context, masterTx repository.MasterTx, name string) (*tagEntity.Entity, error) { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + row := tx.QueryRow(` + SELECT id, name, created_at, updated_at, deleted_at + FROM tags + WHERE name=? + `, name) + result, err := convertToTagEntity(row) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + return result, nil +} + +func (repo *tagRepositoryImplement) SelectByWishCardID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (tagEntity.EntitySlice, error) { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + rows, err := tx.Query(` + SELECT tags.id, tags.name, tags.created_at, tags.updated_at, tags.deleted_at + FROM wish_cards_tags as r + INNER JOIN tags ON tags.id = r.tag_id + WHERE r.wish_card_id=? + `, wishCardID) + if err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + result, err := convertToTagEntitySlice(rows) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + return result, nil +} + +func (repo *tagRepositoryImplement) SelectByMemoryID(ctx context.Context, masterTx repository.MasterTx, memoryID int) (tagEntity.EntitySlice, error) { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + rows, err := tx.Query(` + SELECT tags.id, tags.name, tags.created_at, tags.updated_at, tags.deleted_at + FROM memories_tags as r + INNER JOIN tags ON tags.id = r.tag_id + WHERE r.memory_id=? + `, memoryID) + if err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + result, err := convertToTagEntitySlice(rows) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + return result, nil +} + +func convertToTagEntity(row *sql.Row) (*tagEntity.Entity, error) { + var tag tagEntity.Entity + if err := row.Scan(&tag.ID, &tag.Name, &tag.CreatedAt, &tag.UpdatedAt, &tag.DeletedAt); err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + return nil, werrors.FromConstant(err, werrors.ServerError) + } + return &tag, nil +} + +func convertToTagEntitySlice(rows *sql.Rows) (tagEntity.EntitySlice, error) { + var tags tagEntity.EntitySlice + for rows.Next() { + var tag tagEntity.Entity + if err := rows.Scan(&tag.ID, &tag.Name, &tag.CreatedAt, &tag.UpdatedAt, &tag.DeletedAt); err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + return nil, werrors.FromConstant(err, werrors.ServerError) + } + tags = append(tags, &tag) + } + return tags, nil +} diff --git a/pkg/infrastructure/mysql/tag/repository_test.go b/pkg/infrastructure/mysql/tag/repository_test.go new file mode 100644 index 0000000..13eb4da --- /dev/null +++ b/pkg/infrastructure/mysql/tag/repository_test.go @@ -0,0 +1,303 @@ +package tag + +import ( + "context" + "crypto/rand" + "database/sql" + "errors" + "log" + "os" + "testing" + "time" + tagEntity "wantum/pkg/domain/entity/tag" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/repository/tag" + tx "wantum/pkg/infrastructure/mysql" + "wantum/pkg/testutil" + + _ "github.com/go-sql-driver/mysql" + "github.com/stretchr/testify/assert" +) + +var ( + db *sql.DB + txManager repository.MasterTxManager + repo tag.Repository + dummyDate time.Time + + dummyTagID = 1 +) + +func TestMain(m *testing.M) { + before() + code := m.Run() + after() + os.Exit(code) +} + +// repositoryを作ってもらう +func before() { + var err error + db, err = testutil.ConnectLocalDB() + if err != nil { + log.Fatal("faild to connect db: ", err) + } + txManager = tx.NewDBMasterTxManager(db) + repo = New(txManager) + dummyDate = time.Date(2020, 9, 1, 12, 0, 0, 0, time.Local) +} + +// dbのコネクションを閉じる +func after() { + db.Close() +} + +func TestInsert(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + name, _ := makeRandomStr(10) + tag := &tagEntity.Entity{ + Name: name, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + var result int + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + result, err = repo.Insert(ctx, masterTx, tag) + return err + }) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) +} + +func TestUpDeleteFlag(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + name, _ := makeRandomStr(10) + dummyTime := time.Date(2020, 10, 10, 10, 0, 0, 0, time.Local) + tag := &tagEntity.Entity{ + Name: name, + CreatedAt: &dummyTime, + UpdatedAt: &dummyTime, + } + + var result *tagEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + newTagID, _ := repo.Insert(ctx, masterTx, tag) + + if err = repo.UpDeleteFlag(ctx, masterTx, newTagID, &dummyDate, &dummyDate); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, newTagID) + return nil + }) + + assert.NoError(t, err) + assert.NotNil(t, result.DeletedAt) + assert.Equal(t, dummyDate, result.DeletedAt.Local()) + assert.Equal(t, dummyDate, result.UpdatedAt.Local()) + }) + + t.Run("failure_deletedAtがnil", func(t *testing.T) { + var err error + ctx := context.Background() + + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + return repo.UpDeleteFlag(ctx, masterTx, dummyTagID, &dummyDate, nil) + }) + + assert.Error(t, err) + }) +} + +func TestDownDeleteFlag(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + var result *tagEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + + if err = repo.DownDeleteFlag(ctx, masterTx, dummyTagID, &dummyDate); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, dummyTagID) + return nil + }) + + assert.NoError(t, err) + assert.Nil(t, result.DeletedAt) + }) +} + +func TestDelete(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + name, _ := makeRandomStr(10) + tag := &tagEntity.Entity{ + Name: name, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + var result *tagEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + newTagID, _ := repo.Insert(ctx, masterTx, tag) + tag.ID = newTagID + tag.DeletedAt = &dummyDate + repo.UpDeleteFlag(ctx, masterTx, tag.ID, tag.DeletedAt, tag.DeletedAt) + + if err = repo.Delete(ctx, masterTx, tag); err != nil { + return err + } + + result, err = repo.SelectByID(ctx, masterTx, tag.ID) + if result != nil { + return errors.New("削除されたデータが引っかかった") + } + return nil + }) + + assert.NoError(t, err) + assert.Nil(t, result) + }) +} + +func TestSelectByID(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + name, _ := makeRandomStr(10) + tag := &tagEntity.Entity{ + Name: name, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + var result *tagEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + newTagID, _ := repo.Insert(ctx, masterTx, tag) + + result, err = repo.SelectByID(ctx, masterTx, newTagID) + return err + }) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) +} + +func TestSelectByIDs(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + var result tagEntity.EntitySlice + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + + result, err = repo.SelectByIDs(ctx, masterTx, []int{1, 2, 3}) + return err + }) + + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, 3, len(result)) + }) +} + +func TestSelectByName(t *testing.T) { + t.Run("successe", func(t *testing.T) { + var err error + ctx := context.Background() + name, _ := makeRandomStr(10) + tag := &tagEntity.Entity{ + Name: name, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + } + + var result *tagEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + repo.Insert(ctx, masterTx, tag) + + result, err = repo.SelectByName(ctx, masterTx, name) + return err + }) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) + + t.Run("failure_存在しないデータ", func(t *testing.T) { + var err error + ctx := context.Background() + name, _ := makeRandomStr(10) + + var result *tagEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + + result, err = repo.SelectByName(ctx, masterTx, name) + return err + }) + + assert.NoError(t, err) + assert.Nil(t, result) + }) +} + +func TestSelectByWishCardID(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + var result tagEntity.EntitySlice + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + + result, err = repo.SelectByWishCardID(ctx, masterTx, 4) + return err + }) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) +} + +func TestSelectByMemoryID(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + var result tagEntity.EntitySlice + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + + result, err = repo.SelectByMemoryID(ctx, masterTx, 4) + return err + }) + + assert.NoError(t, err) + assert.NotNil(t, result) + }) +} + +func makeRandomStr(digit uint32) (string, error) { + const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + + b := make([]byte, digit) + if _, err := rand.Read(b); err != nil { + return "", errors.New("unexpected error...") + } + + var result string + for _, v := range b { + result += string(letters[int(v)%len(letters)]) + } + return result, nil +} diff --git a/pkg/infrastructure/mysql/wishcard/repository.go b/pkg/infrastructure/mysql/wishcard/repository.go new file mode 100644 index 0000000..04814fb --- /dev/null +++ b/pkg/infrastructure/mysql/wishcard/repository.go @@ -0,0 +1,487 @@ +package wishcard + +import ( + "context" + "database/sql" + "errors" + "strconv" + "strings" + "time" + placeEntity "wantum/pkg/domain/entity/place" + userEntity "wantum/pkg/domain/entity/user" + wishCardEntity "wantum/pkg/domain/entity/wishcard" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/repository/wishcard" + "wantum/pkg/infrastructure/mysql" + "wantum/pkg/tlog" + "wantum/pkg/werrors" + + "google.golang.org/grpc/codes" +) + +type wishCardRepositoryImplement struct { + masterTxManager repository.MasterTxManager +} + +func New(txManager repository.MasterTxManager) wishcard.Repository { + return &wishCardRepositoryImplement{ + masterTxManager: txManager, + } +} + +func (repo *wishCardRepositoryImplement) Insert(ctx context.Context, masterTx repository.MasterTx, wishCard *wishCardEntity.Entity, categoryID int) (int, error) { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return 0, werrors.FromConstant(err, werrors.ServerError) + } + result, err := tx.Exec(` + INSERT INTO wish_cards( + user_id, activity, description, date, created_at, updated_at, category_id, place_id + ) VALUES (?,?,?,?,?,?,?,?) + `, wishCard.Author.ID, + wishCard.Activity, + wishCard.Description, + wishCard.Date, + wishCard.CreatedAt, + wishCard.UpdatedAt, + categoryID, + wishCard.Place.ID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return 0, werrors.FromConstant(err, werrors.ServerError) + } + id, err := result.LastInsertId() + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return 0, werrors.FromConstant(err, werrors.ServerError) + } + return int(id), nil +} + +func (repo *wishCardRepositoryImplement) Update(ctx context.Context, masterTx repository.MasterTx, wishCard *wishCardEntity.Entity) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE wish_cards + SET + user_id=?, + activity=?, + description=?, + date=?, + done_at=?, + updated_at=?, + place_id=? + WHERE id=? + `, wishCard.Author.ID, + wishCard.Activity, + wishCard.Description, + wishCard.Date, + wishCard.DoneAt, + wishCard.UpdatedAt, + wishCard.Place.ID, + wishCard.ID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardRepositoryImplement) UpdateActivity(ctx context.Context, masterTx repository.MasterTx, wishCardID int, activity string, updatedAt *time.Time) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE wish_cards + SET activity=?, + updated_at=? + WHERE id=? + `, activity, + updatedAt, + wishCardID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardRepositoryImplement) UpdateDescription(ctx context.Context, masterTx repository.MasterTx, wishCardID int, description string, updatedAt *time.Time) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE wish_cards + SET description=?, + updated_at=? + WHERE id=? + `, description, + updatedAt, + wishCardID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil + +} + +func (repo *wishCardRepositoryImplement) UpdateDate(ctx context.Context, masterTx repository.MasterTx, wishCardID int, date, updatedAt *time.Time) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE wish_cards + SET date=?, + updated_at=? + WHERE id=? + `, date, + updatedAt, + wishCardID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardRepositoryImplement) UpdateDoneAt(ctx context.Context, masterTx repository.MasterTx, wishCardID int, doneAt, updatedAt *time.Time) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE wish_cards + SET done_at=?, + updated_at=? + WHERE id=? + `, doneAt, + updatedAt, + wishCardID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardRepositoryImplement) UpdateUserID(ctx context.Context, masterTx repository.MasterTx, wishCardID int, userID int, updatedAt *time.Time) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE wish_cards + SET user_id=?, + updated_at=? + WHERE id=? + `, userID, + updatedAt, + wishCardID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardRepositoryImplement) UpdatePlaceID(ctx context.Context, masterTx repository.MasterTx, wishCardID int, placeID int, updatedAt *time.Time) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE wish_cards + SET place_id=?, + updated_at=? + WHERE id=? + `, placeID, + updatedAt, + wishCardID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardRepositoryImplement) UpdateCategoryID(ctx context.Context, masterTx repository.MasterTx, wishCardID int, categoryID int, updatedAt *time.Time) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE wish_cards + SET category_id=?, + updated_at=? + WHERE id=? + `, categoryID, + updatedAt, + wishCardID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardRepositoryImplement) UpdateWithCategoryID(ctx context.Context, masterTx repository.MasterTx, wishCard *wishCardEntity.Entity, categoryID int) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE wish_cards + SET + user_id=?, + activity=?, + description=?, + date=?, + done_at=?, + updated_at=?, + category_id=?, + place_id=? + WHERE id=? + `, wishCard.Author.ID, + wishCard.Activity, + wishCard.Description, + wishCard.Date, + wishCard.DoneAt, + wishCard.UpdatedAt, + categoryID, + wishCard.Place.ID, + wishCard.ID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardRepositoryImplement) UpDeleteFlag(ctx context.Context, masterTx repository.MasterTx, wishCardID int, updatedAt, deletedAt *time.Time) error { + if deletedAt == nil { + return werrors.Newf( + errors.New("can't up delete flag. deletedAt is nil"), + codes.Internal, + werrors.ServerError.ErrorCode, + werrors.ServerError.ErrorMessageJP, + werrors.ServerError.ErrorMessageEN, + ) + } + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE wish_cards + SET updated_at=?, deleted_at=? + WHERE id=? + `, updatedAt, + deletedAt, + wishCardID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardRepositoryImplement) DownDeleteFlag(ctx context.Context, masterTx repository.MasterTx, wishCardID int, updatedAt *time.Time) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + UPDATE wish_cards + SET updated_at=?, deleted_at=? + WHERE id=? + `, updatedAt, + nil, + wishCardID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardRepositoryImplement) Delete(ctx context.Context, masterTx repository.MasterTx, wishCard *wishCardEntity.Entity) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + DELETE FROM wish_cards + WHERE id=? and deleted_at is not null + `, wishCard.ID) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardRepositoryImplement) SelectByID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) (*wishCardEntity.Entity, error) { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + row := tx.QueryRow(` + SELECT id, user_id, activity, description, date, done_at, created_at, updated_at, deleted_at, place_id + FROM wish_cards + WHERE id=? + `, wishCardID) + wishCard, err := convertToWishCardEntity(row) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + return wishCard, nil +} + +func (repo *wishCardRepositoryImplement) SelectByIDs(ctx context.Context, masterTx repository.MasterTx, wishCardIDs []int) (wishCardEntity.EntitySlice, error) { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + + wishCardIDsStr := make([]string, 0, len(wishCardIDs)) + for _, id := range wishCardIDs { + wishCardIDsStr = append(wishCardIDsStr, strconv.Itoa(id)) + } + + rows, err := tx.Query(` + SELECT id, user_id, activity, description, date, done_at, created_at, updated_at, deleted_at, place_id + FROM wish_cards + WHERE id + IN (` + strings.Join(wishCardIDsStr, ",") + `) + `) + if err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + wishCards, err := convertToWishCardEntitySlice(rows) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + return wishCards, nil +} + +func (repo *wishCardRepositoryImplement) SelectByCategoryID(ctx context.Context, masterTx repository.MasterTx, categryID int) (wishCardEntity.EntitySlice, error) { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + rows, err := tx.Query(` + SELECT id, user_id, activity, description, date, done_at, created_at, updated_at, deleted_at, place_id + FROM wish_cards + WHERE category_id=? + `, categryID) + if err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + wishCards, err := convertToWishCardEntitySlice(rows) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return nil, werrors.FromConstant(err, werrors.ServerError) + } + return wishCards, nil +} + +func convertToWishCardEntity(row *sql.Row) (*wishCardEntity.Entity, error) { + var wishCard wishCardEntity.Entity + var place placeEntity.Entity + var user userEntity.Entity + err := row.Scan( + &wishCard.ID, + &user.ID, + &wishCard.Activity, + &wishCard.Description, + &wishCard.Date, + &wishCard.DoneAt, + &wishCard.CreatedAt, + &wishCard.UpdatedAt, + &wishCard.DeletedAt, + &place.ID) + if err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + return nil, werrors.FromConstant(err, werrors.ServerError) + } + wishCard.Author = &user + wishCard.Place = &place + return &wishCard, nil +} + +func convertToWishCardEntitySlice(rows *sql.Rows) (wishCardEntity.EntitySlice, error) { + var wishCards wishCardEntity.EntitySlice + for rows.Next() { + var wishCard wishCardEntity.Entity + var place placeEntity.Entity + var user userEntity.Entity + err := rows.Scan( + &wishCard.ID, + &user.ID, + &wishCard.Activity, + &wishCard.Description, + &wishCard.Date, + &wishCard.DoneAt, + &wishCard.CreatedAt, + &wishCard.UpdatedAt, + &wishCard.DeletedAt, + &place.ID, + ) + if err != nil { + if err == sql.ErrNoRows { + return nil, nil + } + return nil, werrors.FromConstant(err, werrors.ServerError) + } + wishCard.Author = &user + wishCard.Place = &place + wishCards = append(wishCards, &wishCard) + } + return wishCards, nil +} diff --git a/pkg/infrastructure/mysql/wishcard/repository_test.go b/pkg/infrastructure/mysql/wishcard/repository_test.go new file mode 100644 index 0000000..cfb7fd0 --- /dev/null +++ b/pkg/infrastructure/mysql/wishcard/repository_test.go @@ -0,0 +1,584 @@ +package wishcard + +import ( + "context" + "database/sql" + "log" + "os" + "testing" + "time" + placeEntity "wantum/pkg/domain/entity/place" + userEntity "wantum/pkg/domain/entity/user" + wishCardEntity "wantum/pkg/domain/entity/wishcard" + "wantum/pkg/domain/repository" + wcrepo "wantum/pkg/domain/repository/wishcard" + tx "wantum/pkg/infrastructure/mysql" + "wantum/pkg/testutil" + + _ "github.com/go-sql-driver/mysql" + "github.com/stretchr/testify/assert" +) + +var ( + db *sql.DB + txManager repository.MasterTxManager + repo wcrepo.Repository + dummyDate time.Time + + dummyActivity = "sampleActivity" + dummyDescription = "sampleDescription" + dummyWishCardID = 2 + dummyUserID = 1 + dummyCategoryID = 1 + dummyPlaceID = 1 +) + +func TestMain(m *testing.M) { + before() + code := m.Run() + after() + os.Exit(code) +} + +func before() { + var err error + db, err = testutil.ConnectLocalDB() + if err != nil { + log.Fatal("faild to connect db: ", err) + } + txManager = tx.NewDBMasterTxManager(db) + repo = New(txManager) + dummyDate = time.Date(2020, 9, 1, 12, 0, 0, 0, time.Local) +} + +func after() { + db.Close() +} + +func TestInsert(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + wishCard := &wishCardEntity.Entity{ + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + var result int + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + result, err = repo.Insert(ctx, masterTx, wishCard, 1) + return err + }) + assert.NoError(t, err) + assert.NotEqual(t, 0, result) + }) +} + +func TestUpdate(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + wishCard := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = repo.Update(ctx, masterTx, wishCard); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, 1) + return nil + }) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyActivity, result.Activity) + }) + + t.Run("success_doneAtがnil", func(t *testing.T) { + var err error + ctx := context.Background() + wishCard := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = repo.Update(ctx, masterTx, wishCard); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, 1) + return nil + }) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyActivity, result.Activity) + }) +} + +func TestUpdateActivity(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = repo.UpdateActivity(ctx, masterTx, dummyWishCardID, dummyActivity, &dummyDate); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, dummyWishCardID) + return nil + }) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyActivity, result.Activity) + }) +} + +func TestUpdateDescription(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = repo.UpdateDescription(ctx, masterTx, dummyWishCardID, dummyDescription, &dummyDate); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, dummyWishCardID) + return nil + }) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyDescription, result.Description) + }) +} + +func TestUpdateDate(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = repo.UpdateDate(ctx, masterTx, dummyWishCardID, &dummyDate, &dummyDate); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, dummyWishCardID) + return nil + }) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyDate, result.Date.Local()) + }) +} + +func TestUpdateDoneAt(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = repo.UpdateDoneAt(ctx, masterTx, dummyWishCardID, &dummyDate, &dummyDate); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, dummyWishCardID) + return nil + }) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyDate, result.DoneAt.Local()) + }) +} + +func TestUpdateUserID(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = repo.UpdateUserID(ctx, masterTx, dummyWishCardID, dummyUserID, &dummyDate); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, dummyWishCardID) + return nil + }) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyUserID, result.Author.ID) + }) +} + +func TestUpdatePlaceID(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = repo.UpdatePlaceID(ctx, masterTx, dummyWishCardID, dummyPlaceID, &dummyDate); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, dummyWishCardID) + return nil + }) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyPlaceID, result.Place.ID) + }) +} + +func TestUpdateCategoryID(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = repo.UpdateCategoryID(ctx, masterTx, dummyWishCardID, dummyCategoryID, &dummyDate); err != nil { + return err + } + + return nil + }) + assert.NoError(t, err) + }) +} + +func TestUpdateWithCategoryID(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + wishCard := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + DoneAt: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = repo.UpdateWithCategoryID(ctx, masterTx, wishCard, 1); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, 1) + return nil + }) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyActivity, result.Activity) + }) + + t.Run("success_doneAtがnil", func(t *testing.T) { + var err error + ctx := context.Background() + wishCard := &wishCardEntity.Entity{ + ID: 1, + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + if err = repo.UpdateWithCategoryID(ctx, masterTx, wishCard, 1); err != nil { + return err + } + + result, _ = repo.SelectByID(ctx, masterTx, 1) + return nil + }) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, dummyActivity, result.Activity) + }) +} + +func TestUpDeleteFlag(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + _dummyDate := time.Date(2020, 10, 10, 10, 0, 0, 0, time.Local) + wishCard := &wishCardEntity.Entity{ + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &_dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + newID, _ := repo.Insert(ctx, masterTx, wishCard, 1) + + wishCard.ID = newID + if err = repo.UpDeleteFlag(ctx, masterTx, newID, &dummyDate, &dummyDate); err != nil { + return err + } + result, _ = repo.SelectByID(ctx, masterTx, wishCard.ID) + return nil + }) + assert.NoError(t, err) + assert.NotNil(t, result.DeletedAt) + assert.Equal(t, dummyDate, result.DeletedAt.Local()) + assert.Equal(t, dummyDate, result.UpdatedAt.Local()) + }) + + t.Run("failure_deletedAtがnil", func(t *testing.T) { + var err error + ctx := context.Background() + wishCard := &wishCardEntity.Entity{ + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + newID, _ := repo.Insert(ctx, masterTx, wishCard, 1) + + wishCard.ID = newID + err = repo.UpDeleteFlag(ctx, masterTx, newID, &dummyDate, nil) + return err + }) + assert.Error(t, err) + }) +} + +func TestDownDeleteFlag(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + wishCard := &wishCardEntity.Entity{ + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + DeletedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + newID, _ := repo.Insert(ctx, masterTx, wishCard, 1) + + if err = repo.DownDeleteFlag(ctx, masterTx, newID, &dummyDate); err != nil { + return err + } + result, _ = repo.SelectByID(ctx, masterTx, newID) + return nil + }) + assert.NoError(t, err) + assert.Nil(t, result.DeletedAt) + }) +} + +func TestDelete(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + wishCard := &wishCardEntity.Entity{ + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + newID, _ := repo.Insert(ctx, masterTx, wishCard, 1) + wishCard.ID = newID + repo.UpDeleteFlag(ctx, masterTx, newID, &dummyDate, &dummyDate) + + if err = repo.Delete(ctx, masterTx, wishCard); err != nil { + return err + } + assert.NoError(t, err) + + result, err = repo.SelectByID(ctx, masterTx, wishCard.ID) + assert.NoError(t, err) + + return nil + }) + + assert.Nil(t, result) + }) +} + +func TestSelectByID(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + wishCard := &wishCardEntity.Entity{ + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + newID, _ := repo.Insert(ctx, masterTx, wishCard, 1) + + result, err = repo.SelectByID(ctx, masterTx, newID) + return err + }) + assert.NoError(t, err) + assert.NotNil(t, result) + }) + + t.Run("failure_存在しないデータ", func(t *testing.T) { + var err error + ctx := context.Background() + + var result *wishCardEntity.Entity + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + result, err = repo.SelectByID(ctx, masterTx, -1) + return err + }) + assert.NoError(t, err) + assert.Nil(t, result) + }) +} + +func TestSelectByIDs(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + ids := []int{1, 2, 3} + + var result wishCardEntity.EntitySlice + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + + result, err = repo.SelectByIDs(ctx, masterTx, ids) + return err + }) + assert.NoError(t, err) + assert.NotNil(t, result) + assert.Equal(t, 3, len(result)) + }) +} + +func TestCategoryID(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + wishCard := &wishCardEntity.Entity{ + Author: &userEntity.Entity{ + ID: 1, + }, + Activity: dummyActivity, + Description: dummyDescription, + Date: &dummyDate, + CreatedAt: &dummyDate, + UpdatedAt: &dummyDate, + Place: &placeEntity.Entity{ + ID: 1, + }, + } + var result wishCardEntity.EntitySlice + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + repo.Insert(ctx, masterTx, wishCard, 1) + + result, err = repo.SelectByCategoryID(ctx, masterTx, 1) + return err + }) + assert.NoError(t, err) + assert.NotNil(t, result) + }) + + t.Run("success_存在しないカテゴリ", func(t *testing.T) { + var err error + ctx := context.Background() + + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + + _, err = repo.SelectByCategoryID(ctx, masterTx, -1) + return err + }) + assert.NoError(t, err) + }) +} diff --git a/pkg/infrastructure/mysql/wishcardtag/repository.go b/pkg/infrastructure/mysql/wishcardtag/repository.go new file mode 100644 index 0000000..93a2733 --- /dev/null +++ b/pkg/infrastructure/mysql/wishcardtag/repository.go @@ -0,0 +1,125 @@ +package wishcardtag + +import ( + "context" + "strconv" + "strings" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/repository/wishcardtag" + "wantum/pkg/infrastructure/mysql" + "wantum/pkg/tlog" + "wantum/pkg/werrors" +) + +type wishCardTagRepositoryImplement struct { + masterTxManager repository.MasterTxManager +} + +func New(txManager repository.MasterTxManager) wishcardtag.Repository { + return &wishCardTagRepositoryImplement{ + masterTxManager: txManager, + } +} + +func (repo *wishCardTagRepositoryImplement) Insert(ctx context.Context, masterTx repository.MasterTx, wishCardID, tagID int) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + INSERT INTO wish_cards_tags(wish_card_id, tag_id) + VALUES (?,?) + `, wishCardID, + tagID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardTagRepositoryImplement) BulkInsert(ctx context.Context, masterTx repository.MasterTx, wishCardID int, tagIDs []int) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + + stmt, err := tx.Prepare("INSERT INTO wish_cards_tags(wish_card_id, tag_id) VALUES (?, ?)") + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + for _, tagID := range tagIDs { + _, err = stmt.Exec(wishCardID, tagID) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + } + return nil +} + +func (repo *wishCardTagRepositoryImplement) Delete(ctx context.Context, masterTx repository.MasterTx, wishCardID, tagID int) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + DELETE FROM wish_cards_tags + WHERE wish_card_id = ? and tag_id = ? + `, wishCardID, + tagID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardTagRepositoryImplement) DeleteByWishCardID(ctx context.Context, masterTx repository.MasterTx, wishCardID int) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + _, err = tx.Exec(` + DELETE FROM wish_cards_tags + WHERE wish_card_id = ? + `, wishCardID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} + +func (repo *wishCardTagRepositoryImplement) DeleteByIDs(ctx context.Context, masterTx repository.MasterTx, wishCardID int, tagIDs []int) error { + tx, err := mysql.ExtractTx(masterTx) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + + tagIDsStr := make([]string, 0, len(tagIDs)) + for _, id := range tagIDs { + tagIDsStr = append(tagIDsStr, strconv.Itoa(id)) + } + + _, err = tx.Exec(` + DELETE FROM wish_cards_tags + WHERE wish_card_id = ? + AND tag_id IN (`+strings.Join(tagIDsStr, ",")+`) + `, wishCardID, + ) + if err != nil { + tlog.PrintErrorLogWithCtx(ctx, err) + return werrors.FromConstant(err, werrors.ServerError) + } + return nil +} diff --git a/pkg/infrastructure/mysql/wishcardtag/repository_test.go b/pkg/infrastructure/mysql/wishcardtag/repository_test.go new file mode 100644 index 0000000..2630d55 --- /dev/null +++ b/pkg/infrastructure/mysql/wishcardtag/repository_test.go @@ -0,0 +1,111 @@ +package wishcardtag + +import ( + "context" + "database/sql" + "log" + "os" + "testing" + "time" + "wantum/pkg/domain/repository" + "wantum/pkg/domain/repository/wishcardtag" + tx "wantum/pkg/infrastructure/mysql" + "wantum/pkg/testutil" + + _ "github.com/go-sql-driver/mysql" + "github.com/stretchr/testify/assert" +) + +var ( + db *sql.DB + txManager repository.MasterTxManager + repo wishcardtag.Repository + dummyDate time.Time +) + +func TestMain(m *testing.M) { + before() + code := m.Run() + after() + os.Exit(code) +} + +func before() { + var err error + db, err = testutil.ConnectLocalDB() + if err != nil { + log.Fatal("faild to connect db: ", err) + } + txManager = tx.NewDBMasterTxManager(db) + repo = New(txManager) + dummyDate = time.Date(2020, 9, 1, 12, 0, 0, 0, time.Local) +} + +func after() { + db.Close() +} + +func TestInsert(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + err = repo.Insert(ctx, masterTx, 1, 1) + return err + }) + assert.NoError(t, err) + }) +} + +func TestBulkInsert(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + err = repo.BulkInsert(ctx, masterTx, 1, []int{2, 3, 4}) + return err + }) + assert.NoError(t, err) + }) +} + +func TestDelete(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + err = repo.Delete(ctx, masterTx, 1, 1) + return err + }) + assert.NoError(t, err) + }) +} + +func TestDeleteByWishCardID(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + err = repo.DeleteByWishCardID(ctx, masterTx, 1) + return err + }) + assert.NoError(t, err) + }) +} + +func TestDeleteByIDs(t *testing.T) { + t.Run("success", func(t *testing.T) { + var err error + ctx := context.Background() + + err = txManager.Transaction(ctx, func(ctx context.Context, masterTx repository.MasterTx) error { + err = repo.DeleteByIDs(ctx, masterTx, 1, []int{1, 2, 3}) + return err + }) + assert.NoError(t, err) + }) +} diff --git a/pkg/testutil/connect_db.go b/pkg/testutil/connect_db.go new file mode 100644 index 0000000..0dc397a --- /dev/null +++ b/pkg/testutil/connect_db.go @@ -0,0 +1,38 @@ +package testutil + +import ( + "database/sql" + "fmt" + "os" + "wantum/pkg/constants" + "wantum/pkg/tlog" +) + +func ConnectLocalDB() (*sql.DB, error) { + + dbuser := os.Getenv("MYSQL_USER") + if dbuser == "" { + dbuser = constants.MysqlDefaultUser + } + dbpassword := os.Getenv("MYSQL_PASSWORD") + if dbpassword == "" { + dbpassword = constants.MysqlDefaultPassword + } + dbhost := os.Getenv("MYSQL_HOST") + if dbhost == "" { + dbhost = constants.MysqlDefaultHost + } + dbport := os.Getenv("MYSQL_PORT") + if dbport == "" { + dbport = constants.MysqlDefaultPort + } + dbname := os.Getenv("MYSQL_DATABASE") + if dbname == "" { + dbname = constants.MysqlDefaultName + } + + dataSource := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?parseTime=true", dbuser, dbpassword, dbhost, dbport, dbname) + tlog.GetAppLogger().Info(fmt.Sprintf("connect db: %s", dataSource)) + + return sql.Open("mysql", dataSource) +} diff --git a/pkg/werrors/constants.go b/pkg/werrors/constants.go index ac5cc5b..441ccd3 100644 --- a/pkg/werrors/constants.go +++ b/pkg/werrors/constants.go @@ -1,6 +1,7 @@ package werrors import ( + "fmt" "net/http" "google.golang.org/grpc/codes" @@ -31,4 +32,18 @@ var ( ErrorMessageJP: "リクエスト内容をもう一度見直してください", ErrorMessageEN: "Please check your request", } + WishCardNotFound = &WantumError{ + err: fmt.Errorf("Attempted to update non-existent data"), + GrpcErrorCode: codes.NotFound, + ErrorCode: http.StatusNotFound, + ErrorMessageJP: "存在しない「やりたいこと」です。", + ErrorMessageEN: "the wish card is not exists.", + } + PlaceNotFound = &WantumError{ + err: fmt.Errorf("Attempted to update non-existent data"), + GrpcErrorCode: codes.NotFound, + ErrorCode: http.StatusNotFound, + ErrorMessageJP: "存在しない「場所」です。", + ErrorMessageEN: "the place is not exists.", + } )