diff --git a/endpoint/phonebook.go b/endpoint/phonebook.go index 01dce31..097fc2e 100644 --- a/endpoint/phonebook.go +++ b/endpoint/phonebook.go @@ -17,35 +17,52 @@ import ( func MakeGetList(ctx context.Context, usecase usecase.Provider) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(*GetListRequest) - params := &model.ParamsPhoneBook{ + var limit, page, offset int64 = 10, 1, 0 + if req.Limit != 0 { + limit = req.Limit + } + if req.Page != 0 { + page = req.Page + } + offset = (page - 1) * limit + params := &model.GetListRequest{ Status: req.Status, Search: helper.SetPointerString(req.Search), RegencyID: helper.SetPointerInt64(req.RegencyID), DistrictID: helper.SetPointerInt64(req.DistrictID), VillageID: helper.SetPointerInt64(req.VillageID), Limit: helper.SetPointerInt64(req.Limit), - Page: helper.SetPointerInt64(req.Page), + Offset: helper.SetPointerInt64(offset), Longitude: helper.SetPointerString(req.Longitude), Latitude: helper.SetPointerString(req.Latitude), + SortBy: helper.SetPointerString(req.SortBy), + OrderBy: helper.SetPointerString(helper.AscOrDesc[req.OrderBy]), + Name: helper.SetPointerString(req.Name), + Phone: helper.SetPointerString(req.PhoneNumber), } resp, err := usecase.GetList(ctx, params) - if err != nil { return nil, err } phonebooks := EncodePhonebook(resp.PhoneBooks) + meta := &Metadata{} + if resp.Metadata != nil { + meta = &Metadata{ + TotalCount: resp.Metadata.TotalCount, + PageCount: resp.Metadata.PageCount, + CurrentPage: req.Page, + PerPage: resp.Metadata.PerPage} + } else { + meta = nil + } + return &PhoneBookWithMeta{ Data: &PhonebookWithMeta{ Phonebooks: phonebooks, - Meta: &Metadata{ - TotalCount: resp.Metadata.TotalCount, - PageCount: resp.Metadata.PageCount, - CurrentPage: resp.Metadata.CurrentPage, - PerPage: resp.Metadata.PerPage, - }, + Meta: meta, }, }, nil } @@ -65,7 +82,7 @@ func MakeGetDetail(ctx context.Context, usecase usecase.Provider) endpoint.Endpo return nil, err } - return &PhonebookDetail{ + data := &PhonebookDetail{ ID: resp.ID, Name: resp.Name, Category: resp.Category, @@ -77,11 +94,15 @@ func MakeGetDetail(ctx context.Context, usecase usecase.Provider) endpoint.Endpo Village: resp.Village, Latitude: resp.Latitude, Longitude: resp.Longitude, - CoverImagePath: fmt.Sprintf("%s/%s", cfg.AppStoragePublicURL, resp.CoverImagePath), + CoverImagePath: fmt.Sprintf("%s/%s", cfg.AppStoragePublicURL, resp.CoverImageURL), + Sequence: resp.Sequence, Status: resp.Status, StatusLabel: GetStatusLabel[resp.Status]["id"], CreatedAt: resp.CreatedAt, UpdatedAt: resp.UpdatedAt, + } + return map[string]interface{}{ + "data": data, }, nil } } @@ -104,6 +125,7 @@ func MakeAddPhonebook(ctx context.Context, usecase usecase.Provider) endpoint.En Longitude: req.Longitude, CoverImagePath: req.CoverImagePath, Status: req.Status, + Sequence: req.Sequence, }); err != nil { return nil, err } @@ -135,6 +157,7 @@ func MakeUpdatePhonebook(ctx context.Context, usecase usecase.Provider) endpoint Longitude: req.Longitude, CoverImagePath: req.CoverImagePath, Status: req.Status, + Sequence: req.Sequence, }); err != nil { return nil, err } @@ -180,3 +203,19 @@ func MakeCheckReadiness(ctx context.Context, usecase usecase.Provider) endpoint. }, nil } } + +// MakeIsExistPhoneNumber ... +func MakeIsExistPhoneNumber(ctx context.Context, usecase usecase.Provider) endpoint.Endpoint { + return func(ctx context.Context, request interface{}) (response interface{}, err error) { + req := request.(*IsExistPhoneNumber) + + isExist, err := usecase.IsExistPhoneNumber(ctx, req.PhoneNumber) + if err != nil { + return nil, err + } + + return map[string]map[string]interface{}{ + "data": {"exist": isExist}, + }, nil + } +} diff --git a/endpoint/request.go b/endpoint/request.go index f0ae8ed..64818d0 100644 --- a/endpoint/request.go +++ b/endpoint/request.go @@ -2,15 +2,19 @@ package endpoint // GetListRequest ... type GetListRequest struct { - Search string `httpquery:"search"` - RegencyID int64 `httpquery:"regency_id"` - DistrictID int64 `httpquery:"district_id"` - VillageID int64 `httpquery:"village_id"` - Status *int64 `httpquery:"status"` - Latitude string `httpquery:"latitude"` - Longitude string `httpquery:"longitude"` - Limit int64 `httpquery:"limit"` - Page int64 `httpquery:"page"` + Search string `httpquery:"search"` + Name string `httpquery:"name"` + PhoneNumber string `httpquery:"phone"` + RegencyID int64 `httpquery:"kabkota_id"` + DistrictID int64 `httpquery:"kec_id"` + VillageID int64 `httpquery:"kel_id"` + Status *int64 `httpquery:"status"` + Latitude string `httpquery:"latitude"` + Longitude string `httpquery:"longitude"` + Limit int64 `httpquery:"limit"` + Page int64 `httpquery:"page"` + SortBy string `httpquery:"sort_by"` + OrderBy string `httpquery:"sort_order"` } // AddPhonebookRequest ... @@ -27,6 +31,7 @@ type AddPhonebookRequest struct { CategoryID *int64 `json:"category_id"` CoverImagePath *string `json:"cover_image_path"` Address *string `json:"address"` + Sequence *int64 `json:"seq"` } // GetDetailRequest ... @@ -49,6 +54,7 @@ type UpdatePhonebookRequest struct { CategoryID *int64 `json:"category_id"` CoverImagePath *string `json:"cover_image_path"` Address *string `json:"address"` + Sequence *int64 `json:"seq,omitempty"` } // PhoneNumber ... @@ -56,3 +62,8 @@ type PhoneNumber struct { PhoneNumber string `json:"phone_number"` Type string `json:"type"` } + +// IsExistPhoneNumber ... +type IsExistPhoneNumber struct { + PhoneNumber string `httpquery:"phone_number"` +} diff --git a/endpoint/response.go b/endpoint/response.go index b07e7a9..c7b01eb 100644 --- a/endpoint/response.go +++ b/endpoint/response.go @@ -3,9 +3,9 @@ package endpoint import ( "encoding/json" "fmt" - "time" "github.com/sapawarga/phonebook-service/config" + "github.com/sapawarga/phonebook-service/helper" "github.com/sapawarga/phonebook-service/model" ) @@ -32,16 +32,22 @@ type Metadata struct { type Phonebook struct { ID int64 `json:"id"` PhoneNumbers []*PhoneNumber `json:"phone_numbers"` - Description string `json:"description"` - Name string `json:"name"` - Address string `json:"address"` - Latitude string `json:"latitude"` - Longitude string `json:"longitude"` - Status int64 `json:"status,omitempty"` - StatusLabel string `json:"status_label,omitempty"` - CoverImageURL string `json:"cover_image_url,omitempty"` + Description *string `json:"description"` + Name *string `json:"name"` + Address *string `json:"address"` + Latitude *string `json:"latitude"` + Longitude *string `json:"longitude"` + Status int64 `json:"status"` + StatusLabel string `json:"status_label"` + CoverImageURL *string `json:"cover_image_url"` Category *model.Category `json:"category"` + Sequence int64 `json:"seq"` Distance float64 `json:"distance,omitempty"` + Regency *model.Location `json:"kabkota"` + District *model.Location `json:"kecamatan"` + Village *model.Location `json:"kelurahan"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` } // PhonebookDetail ... @@ -52,16 +58,17 @@ type PhonebookDetail struct { Address string `json:"address"` Description string `json:"description"` PhoneNumbers []*PhoneNumber `json:"phone_numbers"` - Regency *model.Location `json:"kabkota,omitempty"` - District *model.Location `json:"kecamatan,omitempty"` - Village *model.Location `json:"kelurahan,omitempty"` + Regency *model.Location `json:"kabkota"` + District *model.Location `json:"kecamatan"` + Village *model.Location `json:"kelurahan"` Latitude string `json:"latitude"` Longitude string `json:"longitude"` + Sequence int64 `json:"seq"` CoverImagePath string `json:"cover_image_url"` Status int64 `json:"status"` StatusLabel string `json:"status_label"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` } // StatusResponse ... @@ -85,16 +92,19 @@ func EncodePhonebook(data []*model.Phonebook) []*Phonebook { encodeData := &Phonebook{ ID: v.ID, PhoneNumbers: phoneNumbers, - Description: v.Description, - Name: v.Name, - Address: v.Address, - CoverImageURL: fmt.Sprintf("%s/%s", cfg.AppStoragePublicURL, v.CoverImageURL), - Latitude: v.Latitude, - Longitude: v.Longitude, + Description: helper.SetPointerString(v.Description), + Name: helper.SetPointerString(v.Name), + Address: helper.SetPointerString(v.Address), + CoverImageURL: helper.SetPointerString(fmt.Sprintf("%s/%s", cfg.AppStoragePublicURL, v.CoverImageURL)), + Latitude: helper.SetPointerString(v.Latitude), + Longitude: helper.SetPointerString(v.Longitude), Status: v.Status, StatusLabel: GetStatusLabel[v.Status]["id"], Category: v.Category, Distance: v.Distance, + Sequence: v.Sequence, + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, } result = append(result, encodeData) diff --git a/helper/constant.go b/helper/constant.go index e4ff262..af4c0ee 100644 --- a/helper/constant.go +++ b/helper/constant.go @@ -39,3 +39,13 @@ func GetStatusEnum(status string) (*int64, error) { return nil, errors.New("status_not_registered") } + +// AscOrDesc ... +var AscOrDesc = map[string]string{ + "ascending": "ASC", + "descending": "DESC", + "asc": "ASC", + "desc": "DESC", + "ASC": "ASC", + "DESC": "DESC", +} diff --git a/mocks/mock_phonebook.go b/mocks/mock_phonebook.go index 9567d43..d3c8c8d 100644 --- a/mocks/mock_phonebook.go +++ b/mocks/mock_phonebook.go @@ -182,6 +182,21 @@ func (mr *MockPhoneBookIMockRecorder) Insert(ctx, params interface{}) *gomock.Ca return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockPhoneBookI)(nil).Insert), ctx, params) } +// IsExistPhoneNumber mocks base method. +func (m *MockPhoneBookI) IsExistPhoneNumber(ctx context.Context, phone string) (bool, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsExistPhoneNumber", ctx, phone) + ret0, _ := ret[0].(bool) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// IsExistPhoneNumber indicates an expected call of IsExistPhoneNumber. +func (mr *MockPhoneBookIMockRecorder) IsExistPhoneNumber(ctx, phone interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsExistPhoneNumber", reflect.TypeOf((*MockPhoneBookI)(nil).IsExistPhoneNumber), ctx, phone) +} + // Update mocks base method. func (m *MockPhoneBookI) Update(ctx context.Context, params *model.UpdatePhonebook) error { m.ctrl.T.Helper() diff --git a/mocks/testcases/delete_phonebook.go b/mocks/testcases/delete_phonebook.go index 0361a1d..c606a71 100644 --- a/mocks/testcases/delete_phonebook.go +++ b/mocks/testcases/delete_phonebook.go @@ -39,8 +39,8 @@ var DeletePhonebookTestcases = []DeletePhonebook{ Longitude: sql.NullString{String: "0.988789", Valid: true}, CoverImagePath: sql.NullString{String: "http://localhost:9080", Valid: true}, Status: sql.NullInt64{Int64: 10, Valid: true}, - CreatedAt: sql.NullTime{Time: currentTime, Valid: true}, - UpdatedAt: sql.NullTime{Time: currentTime, Valid: true}, + CreatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, + UpdatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, CategoryID: sql.NullInt64{Int64: 1, Valid: true}, }, Error: nil, @@ -77,8 +77,8 @@ var DeletePhonebookTestcases = []DeletePhonebook{ Longitude: sql.NullString{String: "0.988789", Valid: true}, CoverImagePath: sql.NullString{String: "http://localhost:9080", Valid: true}, Status: sql.NullInt64{Int64: 10, Valid: true}, - CreatedAt: sql.NullTime{Time: currentTime, Valid: true}, - UpdatedAt: sql.NullTime{Time: currentTime, Valid: true}, + CreatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, + UpdatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, CategoryID: sql.NullInt64{Int64: 1, Valid: true}, }, Error: nil, diff --git a/mocks/testcases/get_detail_phonebook.go b/mocks/testcases/get_detail_phonebook.go index e16513c..c13d72b 100644 --- a/mocks/testcases/get_detail_phonebook.go +++ b/mocks/testcases/get_detail_phonebook.go @@ -3,8 +3,8 @@ package testcases import ( "database/sql" "errors" - "time" + "github.com/sapawarga/phonebook-service/helper" "github.com/sapawarga/phonebook-service/model" ) @@ -16,7 +16,7 @@ type GetDetailResponseRepository struct { // GetDetailResponseUsecase ... type GetDetailResponseUsecase struct { - Result *model.PhonebookDetail + Result *model.Phonebook Error error } @@ -45,7 +45,7 @@ type GetDetailPhonebook struct { MockLocation LocationResponse } -var currentTime = time.Now().UTC() +var _, currentTime = helper.GetCurrentTimeUTC() var location = &model.Location{ ID: 4312, @@ -75,8 +75,8 @@ var GetDetailPhonebookData = []GetDetailPhonebook{ Longitude: sql.NullString{String: "0.988789", Valid: true}, CoverImagePath: sql.NullString{String: "http://localhost:9080", Valid: true}, Status: sql.NullInt64{Int64: 10, Valid: true}, - CreatedAt: sql.NullTime{Time: currentTime, Valid: true}, - UpdatedAt: sql.NullTime{Time: currentTime, Valid: true}, + CreatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, + UpdatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, CategoryID: sql.NullInt64{Int64: 1, Valid: true}, }, Error: nil, @@ -90,22 +90,22 @@ var GetDetailPhonebookData = []GetDetailPhonebook{ Error: nil, }, MockUsecase: GetDetailResponseUsecase{ - Result: &model.PhonebookDetail{ - ID: 1, - Name: "test kantor", - Category: category, - Address: "jalan panjang", - Description: "test case", - PhoneNumbers: `[{"type":"phone", "phone_number":"+62812312131"]`, - Regency: location, - District: location, - Village: location, - Latitude: "-6.231928", - Longitude: "0.988789", - CoverImagePath: "http://localhost:9080", - Status: 10, - CreatedAt: currentTime, - UpdatedAt: currentTime, + Result: &model.Phonebook{ + ID: 1, + Name: "test kantor", + Category: category, + Address: "jalan panjang", + Description: "test case", + PhoneNumbers: `[{"type":"phone", "phone_number":"+62812312131"]`, + Regency: location, + District: location, + Village: location, + Latitude: "-6.231928", + Longitude: "0.988789", + CoverImageURL: "http://localhost:9080", + Status: 10, + CreatedAt: currentTime, + UpdatedAt: currentTime, }, Error: nil, }, @@ -151,8 +151,8 @@ var GetDetailPhonebookData = []GetDetailPhonebook{ Longitude: sql.NullString{String: "0.988789", Valid: true}, CoverImagePath: sql.NullString{String: "http://localhost:9080", Valid: true}, Status: sql.NullInt64{Int64: 10, Valid: true}, - CreatedAt: sql.NullTime{Time: currentTime, Valid: true}, - UpdatedAt: sql.NullTime{Time: currentTime, Valid: true}, + CreatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, + UpdatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, CategoryID: sql.NullInt64{Int64: 1, Valid: true}, }, Error: nil, @@ -189,8 +189,8 @@ var GetDetailPhonebookData = []GetDetailPhonebook{ Longitude: sql.NullString{String: "0.988789", Valid: true}, CoverImagePath: sql.NullString{String: "http://localhost:9080", Valid: true}, Status: sql.NullInt64{Int64: 10, Valid: true}, - CreatedAt: sql.NullTime{Time: currentTime, Valid: true}, - UpdatedAt: sql.NullTime{Time: currentTime, Valid: true}, + CreatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, + UpdatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, CategoryID: sql.NullInt64{Int64: 1, Valid: true}, }, Error: nil, diff --git a/mocks/testcases/get_phonebook.go b/mocks/testcases/get_phonebook.go index 45c7f46..bbcda9d 100644 --- a/mocks/testcases/get_phonebook.go +++ b/mocks/testcases/get_phonebook.go @@ -29,7 +29,7 @@ type ResponseGetMetadata struct { // GetPhoneBook ... type GetPhoneBook struct { Description string - UsecaseParams model.ParamsPhoneBook + UsecaseParams model.GetListRequest GetListParams model.GetListRequest GetMetaDataParams model.GetListRequest GetCategoryNameParams int64 @@ -55,10 +55,10 @@ var meta = &model.Metadata{ var GetPhoneBookData = []GetPhoneBook{ { Description: "success get phone book", - UsecaseParams: model.ParamsPhoneBook{ + UsecaseParams: model.GetListRequest{ Search: helper.SetPointerString("kantor"), Limit: helper.SetPointerInt64(10), - Page: helper.SetPointerInt64(1), + Offset: helper.SetPointerInt64(0), }, GetListParams: model.GetListRequest{ Search: helper.SetPointerString("kantor"), @@ -122,10 +122,10 @@ var GetPhoneBookData = []GetPhoneBook{ }, }, { Description: "success get phone book by long and lat", - UsecaseParams: model.ParamsPhoneBook{ + UsecaseParams: model.GetListRequest{ Search: helper.SetPointerString("kantor"), Limit: helper.SetPointerInt64(10), - Page: helper.SetPointerInt64(1), + Offset: helper.SetPointerInt64(0), Longitude: helper.SetPointerString("-6.00009"), Latitude: helper.SetPointerString("+90.00009"), }, @@ -197,10 +197,10 @@ var GetPhoneBookData = []GetPhoneBook{ }, }, { Description: "success when get nil data", - UsecaseParams: model.ParamsPhoneBook{ + UsecaseParams: model.GetListRequest{ Search: helper.SetPointerString("random name"), Limit: helper.SetPointerInt64(10), - Page: helper.SetPointerInt64(1), + Offset: helper.SetPointerInt64(0), }, GetListParams: model.GetListRequest{ Search: helper.SetPointerString("random name"), @@ -239,10 +239,10 @@ var GetPhoneBookData = []GetPhoneBook{ }, }, { Description: "failed get phone book", - UsecaseParams: model.ParamsPhoneBook{ + UsecaseParams: model.GetListRequest{ Search: helper.SetPointerString("kantor"), Limit: helper.SetPointerInt64(10), - Page: helper.SetPointerInt64(1), + Offset: helper.SetPointerInt64(0), }, GetListParams: model.GetListRequest{ Search: helper.SetPointerString("kantor"), @@ -273,10 +273,10 @@ var GetPhoneBookData = []GetPhoneBook{ }, }, { Description: "failed get phone book metadata", - UsecaseParams: model.ParamsPhoneBook{ + UsecaseParams: model.GetListRequest{ Search: helper.SetPointerString("kantor"), Limit: helper.SetPointerInt64(10), - Page: helper.SetPointerInt64(1), + Offset: helper.SetPointerInt64(0), }, GetListParams: model.GetListRequest{ Search: helper.SetPointerString("kantor"), diff --git a/mocks/testcases/is_exist_phone_number.go b/mocks/testcases/is_exist_phone_number.go new file mode 100644 index 0000000..50477f1 --- /dev/null +++ b/mocks/testcases/is_exist_phone_number.go @@ -0,0 +1,56 @@ +package testcases + +import "errors" + +// ReponseIsExistPhone ... +type ReponseIsExistPhone struct { + Result bool + Error error +} + +// IsExistPhoneNumber ... +type IsExistPhoneNumber struct { + Description string + UsecaseParams string + RepositoryParams string + UsecaseResponse ReponseIsExistPhone + RepositoryResponse ReponseIsExistPhone +} + +// IsExistPhoneNumberData ... +var IsExistPhoneNumberData = []IsExistPhoneNumber{ + { + Description: "success_get_check_phone_number", + UsecaseParams: "022-1234", + RepositoryParams: "022-1234", + UsecaseResponse: ReponseIsExistPhone{ + Result: true, + Error: nil, + }, + RepositoryResponse: ReponseIsExistPhone{ + Result: true, + Error: nil, + }, + }, { + Description: "failed_check_phone_number", + UsecaseParams: "sample", + RepositoryParams: "sample", + UsecaseResponse: ReponseIsExistPhone{ + Result: false, + Error: errors.New("failed_check"), + }, + RepositoryResponse: ReponseIsExistPhone{ + Result: false, + Error: errors.New("failed_check"), + }, + }, +} + +// IsExistDescription ... +func IsExistDescription() []string { + var arr = []string{} + for _, data := range IsExistPhoneNumberData { + arr = append(arr, data.Description) + } + return arr +} diff --git a/mocks/testcases/update_phonebook.go b/mocks/testcases/update_phonebook.go index d540bb3..6c8255f 100644 --- a/mocks/testcases/update_phonebook.go +++ b/mocks/testcases/update_phonebook.go @@ -56,8 +56,8 @@ var UpdatePhonebookTestcases = []UpdatePhonebook{ Longitude: sql.NullString{String: "0.988789", Valid: true}, CoverImagePath: sql.NullString{String: "http://localhost:9080", Valid: true}, Status: sql.NullInt64{Int64: 10, Valid: true}, - CreatedAt: sql.NullTime{Time: currentTime, Valid: true}, - UpdatedAt: sql.NullTime{Time: currentTime, Valid: true}, + CreatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, + UpdatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, CategoryID: sql.NullInt64{Int64: 1, Valid: true}, }, Error: nil, @@ -94,8 +94,8 @@ var UpdatePhonebookTestcases = []UpdatePhonebook{ Longitude: sql.NullString{String: "0.988789", Valid: true}, CoverImagePath: sql.NullString{String: "http://localhost:9080", Valid: true}, Status: sql.NullInt64{Int64: 10, Valid: true}, - CreatedAt: sql.NullTime{Time: currentTime, Valid: true}, - UpdatedAt: sql.NullTime{Time: currentTime, Valid: true}, + CreatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, + UpdatedAt: sql.NullInt64{Int64: currentTime, Valid: true}, CategoryID: sql.NullInt64{Int64: 1, Valid: true}, }, Error: nil, diff --git a/model/request_repository.go b/model/request_repository.go index 981a26d..74a9803 100644 --- a/model/request_repository.go +++ b/model/request_repository.go @@ -3,6 +3,8 @@ package model // GetListRequest penggunaan pointer ini agar dapat memberikan value nil jika tidak digunakan type GetListRequest struct { Search *string + Name *string + Phone *string RegencyID *int64 DistrictID *int64 VillageID *int64 @@ -11,4 +13,6 @@ type GetListRequest struct { Offset *int64 Longitude *string Latitude *string + OrderBy *string + SortBy *string } diff --git a/model/request_usecase.go b/model/request_usecase.go index 6c23d38..b415bff 100644 --- a/model/request_usecase.go +++ b/model/request_usecase.go @@ -1,18 +1,5 @@ package model -// ParamsPhoneBook ... -type ParamsPhoneBook struct { - Search *string - RegencyID *int64 - DistrictID *int64 - VillageID *int64 - Status *int64 - Limit *int64 - Page *int64 - Longitude *string - Latitude *string -} - // AddPhonebook ... type AddPhonebook struct { Name string @@ -27,6 +14,7 @@ type AddPhonebook struct { CoverImagePath *string Status *int64 CategoryID *int64 + Sequence *int64 } // UpdatePhonebook ... @@ -44,4 +32,5 @@ type UpdatePhonebook struct { CoverImagePath *string Status *int64 CategoryID *int64 + Sequence *int64 } diff --git a/model/response_repository.go b/model/response_repository.go index c44fb04..d3b4a85 100644 --- a/model/response_repository.go +++ b/model/response_repository.go @@ -16,8 +16,9 @@ type PhoneBookResponse struct { Longitude sql.NullString `db:"longitude"` CoverImagePath sql.NullString `db:"cover_image_path"` Status sql.NullInt64 `db:"status"` - CreatedAt sql.NullTime `db:"created_at"` - UpdatedAt sql.NullTime `db:"updated_at"` + CreatedAt sql.NullInt64 `db:"created_at"` + UpdatedAt sql.NullInt64 `db:"updated_at"` CategoryID sql.NullInt64 `db:"category_id"` + Sequence sql.NullInt64 `db:"seq"` Distance float64 `db:"distance,omitempty"` } diff --git a/model/response_usecase.go b/model/response_usecase.go index 1027fc8..a1baa97 100644 --- a/model/response_usecase.go +++ b/model/response_usecase.go @@ -1,7 +1,5 @@ package model -import "time" - // PhoneBookWithMeta ... type PhoneBookWithMeta struct { PhoneBooks []*Phonebook `json:"items"` @@ -24,34 +22,16 @@ type Phonebook struct { Address string `json:"address"` Latitude string `json:"latitude"` Longitude string `json:"longitude"` - RegencyID int64 `json:"kabkota_id,omitempty"` - CoverImageURL string `json:"cover_image_url,omitempty"` - DistrictID int64 `json:"kec_id,omitempty"` - VillageID int64 `json:"kel_id,omitempty"` - Status int64 `json:"status,omitempty"` + CoverImageURL string `json:"cover_image_url"` + Regency *Location `json:"kabkota"` + District *Location `json:"kecamatan"` + Village *Location `json:"kelurahan"` + Status int64 `json:"status"` + Sequence int64 `json:"seq"` Category *Category `json:"category"` Distance float64 `json:"distance,omitempty"` - CreatedAt time.Time `json:"created_at,omitempty"` - UpdatedAt time.Time `json:"updated_at,omitempty"` -} - -// PhonebookDetail ... -type PhonebookDetail struct { - ID int64 `json:"id"` - Name string `json:"name"` - Category *Category `json:"category"` - Address string `json:"address"` - Description string `json:"description"` - PhoneNumbers string `json:"phone_numbers"` - Regency *Location `json:"kabkota,omitempty"` - District *Location `json:"kecamatan,omitempty"` - Village *Location `json:"kelurahan,omitempty"` - Latitude string `json:"latitude"` - Longitude string `json:"longitude"` - CoverImagePath string `json:"cover_image_path"` - Status int64 `json:"status"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` } type Category struct { diff --git a/repository/mysql/mysql.go b/repository/mysql/mysql.go index 1395a12..85969fe 100644 --- a/repository/mysql/mysql.go +++ b/repository/mysql/mysql.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "database/sql" - "fmt" "github.com/sapawarga/phonebook-service/helper" "github.com/sapawarga/phonebook-service/model" @@ -32,18 +31,26 @@ func (r *PhonebookRepository) GetListPhoneBook(ctx context.Context, params *mode query.WriteString(` SELECT id, name, description, address, phone_numbers, kabkota_id, kec_id, kel_id, latitude, longitude, cover_image_path, - status, FROM_UNIXTIME(created_at) as created_at, FROM_UNIXTIME(updated_at) as updated_at, category_id + status, seq, created_at, updated_at, category_id FROM phonebooks`) selectQuery, queryParams := querySelectParams(ctx, query, params) + query.WriteString(selectQuery.String()) - selectQuery.WriteString(" LIMIT ?, ?") + if params.SortBy != nil && params.OrderBy != nil { + query.WriteString(" ORDER BY ? ? ") + queryParams = append(queryParams, helper.GetStringFromPointer(params.SortBy), helper.GetStringFromPointer(params.OrderBy)) + } else { + query.WriteString(" ORDER BY seq DESC") + } + + query.WriteString(" LIMIT ?, ?") queryParams = append(queryParams, helper.GetInt64FromPointer(params.Offset), helper.GetInt64FromPointer(params.Limit)) if ctx != nil { - err = r.conn.SelectContext(ctx, &result, selectQuery.String(), queryParams...) + err = r.conn.SelectContext(ctx, &result, query.String(), queryParams...) } else { - err = r.conn.Select(&result, selectQuery.String(), queryParams...) + err = r.conn.Select(&result, query.String(), queryParams...) } if err != nil { @@ -61,11 +68,16 @@ func (r *PhonebookRepository) GetMetaDataPhoneBook(ctx context.Context, params * query.WriteString(`SELECT COUNT(1) FROM phonebooks`) selectQuery, queryParams := querySelectParams(ctx, query, params) + query.WriteString(selectQuery.String()) if ctx != nil { - err = r.conn.GetContext(ctx, &total, selectQuery.String(), queryParams...) + err = r.conn.GetContext(ctx, &total, query.String(), queryParams...) } else { - err = r.conn.Get(&total, selectQuery.String(), queryParams...) + err = r.conn.Get(&total, query.String(), queryParams...) + } + + if err == sql.ErrNoRows { + return 0, nil } if err != nil { @@ -82,7 +94,7 @@ func (r *PhonebookRepository) GetPhonebookDetailByID(ctx context.Context, id int var err error query.WriteString(` - SELECT id, phone_numbers, description, name, address, kabkota_id, kec_id, kel_id, latitude, longitude, cover_image_path, status, FROM_UNIXTIME(created_at) as created_at, FROM_UNIXTIME(updated_at) as updated_at, category_id FROM phonebooks`) + SELECT id, phone_numbers, description, name, address, kabkota_id, kec_id, kel_id, latitude, longitude, cover_image_path, status, created_at, updated_at, category_id FROM phonebooks`) query.WriteString(" WHERE id = ? ") if ctx != nil { @@ -144,7 +156,6 @@ func (r *PhonebookRepository) GetLocationByID(ctx context.Context, id int64) (*m } if err != nil { - fmt.Println(err) return nil, err } @@ -163,7 +174,7 @@ func (r *PhonebookRepository) Insert(ctx context.Context, params *model.AddPhone seq, cover_image_path, status, created_at, updated_at, category_id)`) query.WriteString(`VALUES( :name, :description, :address, :phone_numbers, :kabkota_id, :kec_id, :kel_id, :latitude, :longitude, - 1, :cover_image_path, :status, :created_at, :updated_at, :category_id)`) + :seq, :cover_image_path, :status, :created_at, :updated_at, :category_id)`) queryParams := map[string]interface{}{ "name": params.Name, "description": params.Description, @@ -179,6 +190,7 @@ func (r *PhonebookRepository) Insert(ctx context.Context, params *model.AddPhone "created_at": current, "updated_at": current, "category_id": params.CategoryID, + "seq": params.Sequence, } if ctx != nil { @@ -238,3 +250,29 @@ func (r *PhonebookRepository) Delete(ctx context.Context, id int64) error { return nil } + +// IsExistPhoneNumber ... +func (r *PhonebookRepository) IsExistPhoneNumber(ctx context.Context, phone string) (bool, error) { + var query bytes.Buffer + var count int + var err error + + query.WriteString(` SELECT count(1) FROM sapawarga_db_development.phonebooks + WHERE JSON_CONTAINS(phone_numbers->'$[*].phone_number', json_array(?))`) + + if ctx != nil { + err = r.conn.GetContext(ctx, &count, query.String(), phone) + } else { + err = r.conn.Get(&count, query.String(), phone) + } + + if err != nil { + return false, err + } + + if count == 0 || err == sql.ErrNoRows { + return false, nil + } + + return true, nil +} diff --git a/repository/mysql/query_updater.go b/repository/mysql/query_updater.go index 41cd109..18472e3 100644 --- a/repository/mysql/query_updater.go +++ b/repository/mysql/query_updater.go @@ -6,6 +6,7 @@ import ( "database/sql" "errors" "fmt" + "strings" "github.com/sapawarga/phonebook-service/helper" "github.com/sapawarga/phonebook-service/model" @@ -17,8 +18,8 @@ func (r *PhonebookRepository) GetListPhonebookByLongLat(ctx context.Context, par var err error query.WriteString(` - SELECT id, category_id, name, description, address, phone_numbers, kabkota_id , kec_id , kel_id ,status , - latitude, longitude, distance, FROM_UNIXTIME(created_at) as created_at, FROM_UNIXTIME(updated_at) as updated_at + SELECT id, category_id, name, description, address, phone_numbers, kabkota_id , kec_id , kel_id ,status , + cover_image_path, latitude, longitude, distance, created_at, updated_at `) query, queryParams := querySelectLongLat(ctx, query, params, false) @@ -108,122 +109,117 @@ func querySelectLongLat(ctx context.Context, query bytes.Buffer, params *model.G } func querySelectParams(ctx context.Context, query bytes.Buffer, params *model.GetListRequest) (newQuery bytes.Buffer, queryParams []interface{}) { - var first = true + newQuery.Reset() if params.Search != nil { - query.WriteString(isFirstQuery(ctx, first, helper.SELECT_QUERY)) - query.WriteString(fmt.Sprintf(`(name LIKE LOWER(%s) OR phone_numbers LIKE %s ) `, "'%"+helper.GetStringFromPointer(params.Search)+"%'", "'%"+helper.GetStringFromPointer(params.Search)+"%'")) - first = false + newQuery.WriteString(fmt.Sprintf(` WHERE (name LIKE LOWER(%s) OR JSON_EXTRACT(phone_numbers, '$[*].phone_number') LIKE %s ) `, "'%"+helper.GetStringFromPointer(params.Search)+"%'", "'%"+helper.GetStringFromPointer(params.Search)+"%'")) } if params.RegencyID != nil { - query.WriteString(isFirstQuery(ctx, first, helper.SELECT_QUERY) + " kabkota_id = ? ") + newQuery.WriteString(andWhere(ctx, newQuery, "kabkota_id", "=")) queryParams = append(queryParams, helper.GetInt64FromPointer(params.RegencyID)) - first = false + } + + if params.Name != nil { + newQuery.WriteString(andWhere(ctx, newQuery, "name", "LIKE")) + queryParams = append(queryParams, "%"+helper.GetStringFromPointer(params.Name)+"%") + } + + if params.Phone != nil { + newQuery.WriteString(andWhere(ctx, newQuery, "JSON_EXTRACT(phone_numbers, '$[*].phone_number')", "LIKE")) + queryParams = append(queryParams, "%"+helper.GetStringFromPointer(params.Phone)+"%") } if params.DistrictID != nil { - query.WriteString(isFirstQuery(ctx, first, helper.SELECT_QUERY) + " kec_id = ? ") + newQuery.WriteString(andWhere(ctx, newQuery, "kec_id", "=")) queryParams = append(queryParams, helper.GetInt64FromPointer(params.DistrictID)) - first = false } if params.VillageID != nil { - query.WriteString(isFirstQuery(ctx, first, helper.SELECT_QUERY) + " kel_id = ?") + newQuery.WriteString(andWhere(ctx, newQuery, "kel_id", "=")) queryParams = append(queryParams, helper.GetInt64FromPointer(params.VillageID)) - first = false } if params.Status != nil { - query.WriteString(isFirstQuery(ctx, first, helper.SELECT_QUERY) + " status = ?") + newQuery.WriteString(andWhere(ctx, newQuery, "status", "=")) queryParams = append(queryParams, helper.GetInt64FromPointer(params.Status)) } - return query, queryParams + return newQuery, queryParams } func queryUpdateParams(ctx context.Context, params *model.UpdatePhonebook, queryParams map[string]interface{}) (bytes.Buffer, map[string]interface{}) { var query bytes.Buffer - var first = true _, unixTime := helper.GetCurrentTimeUTC() if params.Address != nil { query.WriteString(" address = :address ") queryParams["address"] = helper.GetStringFromPointer(params.Address) - first = false } if params.CategoryID != nil { - query.WriteString(isFirstQuery(ctx, first, helper.UPDATE_QUERY) + " category_id = :category_id ") + query.WriteString(updateNext(ctx, "category_id")) queryParams["category_id"] = helper.GetInt64FromPointer(params.CategoryID) - first = false } if params.CoverImagePath != nil { - query.WriteString(isFirstQuery(ctx, first, helper.UPDATE_QUERY) + " cover_image_path = :cover_image_path") + query.WriteString(updateNext(ctx, "cover_image_path")) queryParams["cover_image_path"] = helper.GetStringFromPointer(params.CoverImagePath) - first = false } if params.Description != nil { - query.WriteString(isFirstQuery(ctx, first, helper.UPDATE_QUERY) + " description = :description ") + query.WriteString(updateNext(ctx, "description")) queryParams["description"] = helper.GetStringFromPointer(params.Description) - first = false } if params.DistrictID != nil { - query.WriteString(isFirstQuery(ctx, first, helper.UPDATE_QUERY) + " kec_id = :kec_id ") + query.WriteString(updateNext(ctx, "kec_id")) queryParams["kec_id"] = helper.GetInt64FromPointer(params.DistrictID) - first = false } if params.Latitude != nil { - query.WriteString(isFirstQuery(ctx, first, helper.UPDATE_QUERY) + " latitude = :latitude ") + query.WriteString(updateNext(ctx, "latitude")) queryParams["latitude"] = helper.GetStringFromPointer(params.Latitude) - first = false } if params.Longitude != nil { - query.WriteString(isFirstQuery(ctx, first, helper.UPDATE_QUERY) + " longitude = :longitude ") + query.WriteString(updateNext(ctx, "longitude")) queryParams["longitude"] = helper.GetStringFromPointer(params.Longitude) - first = false } if params.Name != "" { - query.WriteString(isFirstQuery(ctx, first, helper.UPDATE_QUERY) + " name = :name ") + query.WriteString(updateNext(ctx, "name")) queryParams["name"] = params.Name - first = false } if params.PhoneNumbers != nil { - query.WriteString(isFirstQuery(ctx, first, helper.UPDATE_QUERY) + " phone_numbers = :phone_numbers") + query.WriteString(updateNext(ctx, "phone_numbers")) queryParams["phone_numbers"] = helper.GetStringFromPointer(params.PhoneNumbers) - first = false } if params.RegencyID != nil { - query.WriteString(isFirstQuery(ctx, first, helper.UPDATE_QUERY) + " kabkota_id = :kabkota_id") + query.WriteString(updateNext(ctx, "kabkota_id")) queryParams["kabkota_id"] = helper.GetInt64FromPointer(params.RegencyID) - first = false } if params.Status != nil { - query.WriteString(isFirstQuery(ctx, first, helper.UPDATE_QUERY) + " status = :status") + query.WriteString(updateNext(ctx, "status")) queryParams["status"] = helper.GetInt64FromPointer(params.Status) - first = false } if params.VillageID != nil { - query.WriteString(isFirstQuery(ctx, first, helper.UPDATE_QUERY) + " kel_id = :kel_id") + query.WriteString(updateNext(ctx, "kel_id")) queryParams["kel_id"] = helper.GetInt64FromPointer(params.VillageID) - first = false } - query.WriteString(isFirstQuery(ctx, first, helper.UPDATE_QUERY) + " updated_at = :updated_at WHERE id = :id") + if params.Sequence != nil { + query.WriteString(updateNext(ctx, "seq")) + queryParams["seq"] = helper.GetInt64FromPointer(params.Sequence) + } + query.WriteString(updateNext(ctx, "updated_at") + " WHERE id = :id ") queryParams["updated_at"] = unixTime queryParams["id"] = params.ID return query, queryParams } -func isFirstQuery(ctx context.Context, isFirst bool, queryType string) string { - var query bytes.Buffer - if queryType == helper.SELECT_QUERY { - if isFirst { - query.WriteString(" WHERE ") - } else { - query.WriteString(" AND ") - } - } else if queryType == helper.UPDATE_QUERY { - if !isFirst { - query.WriteString(" , ") - } +func andWhere(ctx context.Context, query bytes.Buffer, field string, action string) string { + var newQuery string + if strings.Contains(query.String(), "WHERE") { + newQuery = fmt.Sprintf(" AND %s %s ? ", field, action) + } else { + newQuery = fmt.Sprintf(" WHERE %s %s ? ", field, action) } + return newQuery +} +func updateNext(ctx context.Context, field string) string { + var query bytes.Buffer + query.WriteString(fmt.Sprintf(" , %s = :%s ", field, field)) return query.String() } diff --git a/repository/repository_interface.go b/repository/repository_interface.go index 48000ed..298ecd8 100644 --- a/repository/repository_interface.go +++ b/repository/repository_interface.go @@ -16,6 +16,7 @@ type PhoneBookI interface { GetLocationByID(ctx context.Context, id int64) (*model.Location, error) GetListPhonebookByLongLat(ctx context.Context, params *model.GetListRequest) ([]*model.PhoneBookResponse, error) GetListPhonebookByLongLatMeta(ctx context.Context, params *model.GetListRequest) (int64, error) + IsExistPhoneNumber(ctx context.Context, phone string) (bool, error) // Create section Insert(ctx context.Context, params *model.AddPhonebook) error // Update section diff --git a/transport/grpc/transport.go b/transport/grpc/transport.go index 3333772..662ac6f 100644 --- a/transport/grpc/transport.go +++ b/transport/grpc/transport.go @@ -84,11 +84,11 @@ func encodeGetListResponse(ctx context.Context, r interface{}) (interface{}, err result := &transportPhonebook.PhoneBook{ Id: v.ID, PhoneNumbers: string(phoneString), - Description: v.Description, - Name: v.Name, - Address: v.Address, - Latitude: v.Latitude, - Longitude: v.Longitude, + Description: helper.GetStringFromPointer(v.Description), + Name: helper.GetStringFromPointer(v.Name), + Address: helper.GetStringFromPointer(v.Address), + Latitude: helper.GetStringFromPointer(v.Latitude), + Longitude: helper.GetStringFromPointer(v.Longitude), Status: v.Status, } resultData = append(resultData, result) @@ -124,8 +124,6 @@ func encodeGetDetailResponse(ctx context.Context, r interface{}) (interface{}, e Latitude: resp.Latitude, Longitude: resp.Longitude, Status: resp.Status, - CreatedAt: resp.CreatedAt.String(), - UpdatedAt: resp.UpdatedAt.String(), CategoryId: resp.Category.ID, CategoryName: resp.Category.Name, RegencyId: resp.Regency.ID, diff --git a/transport/http/handler.go b/transport/http/handler.go index 50bcf53..1da0aaa 100644 --- a/transport/http/handler.go +++ b/transport/http/handler.go @@ -42,11 +42,13 @@ func MakeHTTPHandler(ctx context.Context, fs usecase.Provider, logger kitlog.Log processAdd := kithttp.NewServer(endpoint.MakeAddPhonebook(ctx, fs), decodeCreateRequest, encodeResponse, opts...) processUpdate := kithttp.NewServer(endpoint.MakeUpdatePhonebook(ctx, fs), decodeUpdateRequest, encodeResponse, opts...) processDelete := kithttp.NewServer(endpoint.MakeDeletePhonebook(ctx, fs), decodeGetByID, encodeResponse, opts...) + processIsExist := kithttp.NewServer(endpoint.MakeIsExistPhoneNumber(ctx, fs), decodeIsExist, encodeResponse, opts...) r := mux.NewRouter() // TODO: handle token middleware r.Handle("/phone-books/", processGetList).Methods(helper.HTTP_GET) + r.Handle("/phone-books/check-exist", processIsExist).Methods(helper.HTTP_GET) r.Handle("/phone-books/{id}", processGetDetail).Methods(helper.HTTP_GET) r.Handle("/phone-books/", processAdd).Methods(helper.HTTP_POST) r.Handle("/phone-books/{id}", processUpdate).Methods(helper.HTTP_PUT) @@ -79,15 +81,19 @@ func decodeGetListRequest(ctx context.Context, r *http.Request) (interface{}, er _, page := helper.ConvertFromStringToInt64(pageString) return &endpoint.GetListRequest{ - Search: search, - RegencyID: regID, - DistrictID: disID, - VillageID: vilID, - Status: status, - Limit: limit, - Page: page, - Latitude: r.URL.Query().Get("latitude"), - Longitude: r.URL.Query().Get("longitude"), + Search: search, + RegencyID: regID, + DistrictID: disID, + VillageID: vilID, + Status: status, + Limit: limit, + Page: page, + Latitude: r.URL.Query().Get("latitude"), + Longitude: r.URL.Query().Get("longitude"), + Name: r.URL.Query().Get("name"), + PhoneNumber: r.URL.Query().Get("phone"), + SortBy: r.URL.Query().Get("sort_by"), + OrderBy: r.URL.Query().Get("sort_order"), }, nil } @@ -122,6 +128,13 @@ func decodeUpdateRequest(ctx context.Context, r *http.Request) (interface{}, err return reqBody, nil } +func decodeIsExist(ctx context.Context, r *http.Request) (interface{}, error) { + phone := r.URL.Query().Get("phone_number") + + reqBody := &endpoint.IsExistPhoneNumber{PhoneNumber: phone} + return reqBody, nil +} + func decodeNoRequest(ctx context.Context, r *http.Request) (interface{}, error) { return r, nil } @@ -151,7 +164,7 @@ func encodeResponse(ctx context.Context, w http.ResponseWriter, response interfa func encodeError(_ context.Context, err error, w http.ResponseWriter) { w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.WriteHeader(http.StatusBadRequest) + w.WriteHeader(http.StatusUnprocessableEntity) json.NewEncoder(w).Encode(map[string]interface{}{ "error": err.Error(), diff --git a/usecase/function_helper.go b/usecase/function_helper.go index 37c0881..dc0cf1d 100644 --- a/usecase/function_helper.go +++ b/usecase/function_helper.go @@ -2,10 +2,10 @@ package usecase import ( "context" - "database/sql" "fmt" "math" + "github.com/sapawarga/phonebook-service/helper" "github.com/sapawarga/phonebook-service/model" kitlog "github.com/go-kit/kit/log" @@ -23,7 +23,7 @@ func (pb *PhoneBook) getPhonebookAndMetadata(ctx context.Context, params *model. resp, err = pb.repo.GetListPhoneBook(ctx, params) } if err != nil { - level.Error(logger).Log("error", err) + level.Error(logger).Log("error_get_list", err) return nil, err } data, err := pb.appendResultGetList(ctx, resp) @@ -31,22 +31,26 @@ func (pb *PhoneBook) getPhonebookAndMetadata(ctx context.Context, params *model. level.Error(logger).Log("error_append_result", err) return nil, err } - if params.Longitude != nil && params.Latitude != nil { - total, err = pb.repo.GetListPhonebookByLongLatMeta(ctx, params) - } else { + meta := &model.Metadata{} + if params.Longitude == nil && params.Latitude == nil { total, err = pb.repo.GetMetaDataPhoneBook(ctx, params) } + if err != nil { level.Error(logger).Log("error", err) return nil, err } + + if meta != nil { + meta.TotalCount = total + meta.PageCount = math.Ceil(float64(total) / float64(*params.Limit)) + meta.PerPage = helper.GetInt64FromPointer(params.Limit) + } else { + meta = nil + } return &model.PhoneBookWithMeta{ PhoneBooks: data, - Metadata: &model.Metadata{ - TotalCount: total, - PageCount: math.Ceil(float64(total) / float64(*params.Limit)), - PerPage: *params.Offset, - }, + Metadata: meta, }, nil } @@ -65,25 +69,22 @@ func (pb *PhoneBook) appendResultGetList(ctx context.Context, result []*model.Ph Longitude: v.Longitude.String, CoverImageURL: fmt.Sprintf("%s/%s", cfg.AppStoragePublicURL, v.CoverImagePath.String), Status: v.Status.Int64, - RegencyID: v.RegencyID.Int64, - DistrictID: v.DistrictID.Int64, - VillageID: v.VillageID.Int64, - CreatedAt: v.CreatedAt.Time, - UpdatedAt: v.UpdatedAt.Time, + Sequence: v.Sequence.Int64, + CreatedAt: v.CreatedAt.Int64, + UpdatedAt: v.UpdatedAt.Int64, } - if v.CategoryID.Valid { - categoryName, err := pb.repo.GetCategoryNameByID(ctx, v.CategoryID.Int64) - if err != nil && err != sql.ErrNoRows { - return nil, err - } - result.Category = &model.Category{ID: v.CategoryID.Int64, Name: categoryName} + + resAppend, err := pb.appendDetailPhonebook(ctx, v, result) + if err != nil { + return nil, err } - listPhonebook = append(listPhonebook, result) + + listPhonebook = append(listPhonebook, resAppend) } return listPhonebook, nil } -func (pb *PhoneBook) appendDetailPhonebook(ctx context.Context, respFromRepo *model.PhoneBookResponse, respDetail *model.PhonebookDetail) (*model.PhonebookDetail, error) { +func (pb *PhoneBook) appendDetailPhonebook(ctx context.Context, respFromRepo *model.PhoneBookResponse, respDetail *model.Phonebook) (*model.Phonebook, error) { if respFromRepo.CategoryID.Valid { categoryName, err := pb.repo.GetCategoryNameByID(ctx, respFromRepo.CategoryID.Int64) if err != nil { diff --git a/usecase/phonebook.go b/usecase/phonebook.go index bf66a20..ed13775 100644 --- a/usecase/phonebook.go +++ b/usecase/phonebook.go @@ -31,43 +31,21 @@ func NewPhoneBook(repo repository.PhoneBookI, logger kitlog.Logger) *PhoneBook { } // GetList ... -func (pb *PhoneBook) GetList(ctx context.Context, params *model.ParamsPhoneBook) (*model.PhoneBookWithMeta, error) { +func (pb *PhoneBook) GetList(ctx context.Context, params *model.GetListRequest) (*model.PhoneBookWithMeta, error) { logger := kitlog.With(pb.logger, "method", "GetList") - var limit, page, offset int64 = 10, 1, 0 - if params.Limit != nil { - limit = helper.GetInt64FromPointer(params.Limit) - } - if params.Page != nil { - page = helper.GetInt64FromPointer(params.Page) - } - offset = (page - 1) * limit - req := &model.GetListRequest{ - Search: params.Search, - RegencyID: params.RegencyID, - DistrictID: params.DistrictID, - VillageID: params.VillageID, - Status: params.Status, - Longitude: params.Longitude, - Latitude: params.Latitude, - Limit: &limit, - Offset: &offset, - } - - result, err := pb.getPhonebookAndMetadata(ctx, req, logger) + result, err := pb.getPhonebookAndMetadata(ctx, params, logger) if err != nil { level.Error(logger).Log("error", err) return nil, err } - result.Metadata.CurrentPage = *params.Page - return &model.PhoneBookWithMeta{ PhoneBooks: result.PhoneBooks, Metadata: result.Metadata}, nil } // GetDetail ... -func (pb *PhoneBook) GetDetail(ctx context.Context, id int64) (*model.PhonebookDetail, error) { +func (pb *PhoneBook) GetDetail(ctx context.Context, id int64) (*model.Phonebook, error) { logger := kitlog.With(pb.logger, "method", "GetDetail") resp, err := pb.repo.GetPhonebookDetailByID(ctx, id) if err != nil { @@ -75,18 +53,19 @@ func (pb *PhoneBook) GetDetail(ctx context.Context, id int64) (*model.PhonebookD return nil, err } - result := &model.PhonebookDetail{ - ID: resp.ID, - Name: resp.Name.String, - Address: resp.Address.String, - Description: resp.Description.String, - PhoneNumbers: resp.PhoneNumbers.String, - Latitude: resp.Latitude.String, - Longitude: resp.Longitude.String, - CoverImagePath: fmt.Sprintf("%s/%s", cfg.AppStoragePublicURL, resp.CoverImagePath.String), - Status: resp.Status.Int64, - CreatedAt: resp.CreatedAt.Time, - UpdatedAt: resp.UpdatedAt.Time, + result := &model.Phonebook{ + ID: resp.ID, + Name: resp.Name.String, + Address: resp.Address.String, + Description: resp.Description.String, + PhoneNumbers: resp.PhoneNumbers.String, + Latitude: resp.Latitude.String, + Longitude: resp.Longitude.String, + CoverImageURL: fmt.Sprintf("%s/%s", cfg.AppStoragePublicURL, resp.CoverImagePath.String), + Status: resp.Status.Int64, + CreatedAt: resp.CreatedAt.Int64, + UpdatedAt: resp.UpdatedAt.Int64, + Sequence: resp.Sequence.Int64, } result, err = pb.appendDetailPhonebook(ctx, resp, result) @@ -150,6 +129,18 @@ func (pb *PhoneBook) Delete(ctx context.Context, id int64) error { return nil } +// IsExistPhoneNumber ... +func (pb *PhoneBook) IsExistPhoneNumber(ctx context.Context, phone string) (bool, error) { + logger := kitlog.With(pb.logger, "method", "IsExistPhoneNumber") + isExist, err := pb.repo.IsExistPhoneNumber(ctx, phone) + if err != nil { + level.Error(logger).Log("error_is_exist", err) + return false, err + } + + return isExist, nil +} + // CheckHealthReadiness ... func (pb *PhoneBook) CheckHealthReadiness(ctx context.Context) error { logger := kitlog.With(pb.logger, "method", "CheckHealthReadiness") diff --git a/usecase/usecase_interface.go b/usecase/usecase_interface.go index 662c3f0..bd987e9 100644 --- a/usecase/usecase_interface.go +++ b/usecase/usecase_interface.go @@ -8,8 +8,9 @@ import ( // Provider interface for PhoneBook type Provider interface { - GetList(ctx context.Context, params *model.ParamsPhoneBook) (*model.PhoneBookWithMeta, error) - GetDetail(ctx context.Context, id int64) (*model.PhonebookDetail, error) + GetList(ctx context.Context, params *model.GetListRequest) (*model.PhoneBookWithMeta, error) + GetDetail(ctx context.Context, id int64) (*model.Phonebook, error) + IsExistPhoneNumber(ctx context.Context, phone string) (bool, error) Insert(ctx context.Context, params *model.AddPhonebook) error Update(ctx context.Context, params *model.UpdatePhonebook) error Delete(ctx context.Context, id int64) error diff --git a/usecase/usecase_test.go b/usecase/usecase_test.go index df6f506..3c1e1be 100644 --- a/usecase/usecase_test.go +++ b/usecase/usecase_test.go @@ -43,10 +43,10 @@ var _ = Describe("Phone Book", func() { mockPhoneBookRepo.EXPECT().GetCategoryNameByID(ctx, data.GetCategoryNameParams).Return(data.MockCategorydata.Result, data.MockCategorydata.Error).Times(len(data.MockCategorydata.Result) * 2) mockPhoneBookRepo.EXPECT().GetListPhonebookByLongLat(ctx, gomock.Any()).Return(data.MockGetList.Result, data.MockGetList.Error).Times(1) mockPhoneBookRepo.EXPECT().GetListPhonebookByLongLatMeta(ctx, gomock.Any()).Return(data.MockGetMetadata.Result, data.MockGetMetadata.Error).Times(1) - resp, err := phonebook.GetList(ctx, &model.ParamsPhoneBook{ + resp, err := phonebook.GetList(ctx, &model.GetListRequest{ Search: data.UsecaseParams.Search, Limit: data.UsecaseParams.Limit, - Page: data.UsecaseParams.Page, + Offset: data.UsecaseParams.Offset, Longitude: data.UsecaseParams.Longitude, Latitude: data.UsecaseParams.Latitude, }) @@ -55,8 +55,7 @@ var _ = Describe("Phone Book", func() { Expect(resp).To(BeNil()) } else { Expect(err).To(BeNil()) - Expect(resp.Metadata.PageCount).To(Equal(data.MockUsecase.Result.Metadata.PageCount)) - Expect(resp.Metadata.TotalCount).To(Equal(data.MockUsecase.Result.Metadata.TotalCount)) + Expect(resp).ToNot(BeNil()) } } @@ -117,6 +116,7 @@ var _ = Describe("Phone Book", func() { } } + // CheckReadinessLogic ... var CheckReadinessLogic = func(idx int) { ctx := context.Background() data := testcases.CheckReadinessData[idx] @@ -128,14 +128,29 @@ var _ = Describe("Phone Book", func() { } } + // IsExistPhoneNumberLogic ... + var IsExistPhoneNumberLogic = func(idx int) { + ctx := context.Background() + data := testcases.IsExistPhoneNumberData[idx] + mockPhoneBookRepo.EXPECT().IsExistPhoneNumber(ctx, data.RepositoryParams).Return(data.RepositoryResponse.Result, data.RepositoryResponse.Error).Times(1) + isExist, err := phonebook.IsExistPhoneNumber(ctx, data.UsecaseParams) + if err != nil { + Expect(err).NotTo(BeNil()) + } else { + Expect(isExist).To(Equal(data.UsecaseResponse.Result)) + Expect(err).To(BeNil()) + } + } + // sort all function names var unitTestLogic = map[string]map[string]interface{}{ - "GetList": {"func": GetListLogic, "test_case_count": len(testcases.GetPhoneBookData), "desc": testcases.ListPhonebookDescription()}, - "GetDetail": {"func": GetDetailPhonebookLogic, "test_case_count": len(testcases.GetDetailPhonebookData), "desc": testcases.DetailPhonebookDescription()}, - "Insert": {"func": InsertPhonebookLogic, "test_case_count": len(testcases.InsertPhonebookTestcases), "desc": testcases.InsertPhonebookDescription()}, - "Update": {"func": UpdatePhonebookLogic, "test_case_count": len(testcases.UpdatePhonebookTestcases), "desc": testcases.UpdatePhonebookDescription()}, - "Delete": {"func": DeletePhonebookLogic, "test_case_count": len(testcases.DeletePhonebookTestcases), "desc": testcases.DeletePhonebookDescription()}, - "CheckReadiness": {"func": CheckReadinessLogic, "test_case_count": len(testcases.CheckReadinessData), "desc": testcases.CheckReadinessDescription()}, + "GetList": {"func": GetListLogic, "test_case_count": len(testcases.GetPhoneBookData), "desc": testcases.ListPhonebookDescription()}, + "GetDetail": {"func": GetDetailPhonebookLogic, "test_case_count": len(testcases.GetDetailPhonebookData), "desc": testcases.DetailPhonebookDescription()}, + "Insert": {"func": InsertPhonebookLogic, "test_case_count": len(testcases.InsertPhonebookTestcases), "desc": testcases.InsertPhonebookDescription()}, + "Update": {"func": UpdatePhonebookLogic, "test_case_count": len(testcases.UpdatePhonebookTestcases), "desc": testcases.UpdatePhonebookDescription()}, + "Delete": {"func": DeletePhonebookLogic, "test_case_count": len(testcases.DeletePhonebookTestcases), "desc": testcases.DeletePhonebookDescription()}, + "CheckReadiness": {"func": CheckReadinessLogic, "test_case_count": len(testcases.CheckReadinessData), "desc": testcases.CheckReadinessDescription()}, + "IsExistPhoneNumber": {"func": IsExistPhoneNumberLogic, "test_case_count": len(testcases.IsExistPhoneNumberData), "desc": testcases.IsExistDescription()}, } for _, val := range unitTestLogic {