diff --git a/api/BaseResponse.go b/api/BaseResponse.go index ae46a0c..8cbd817 100755 --- a/api/BaseResponse.go +++ b/api/BaseResponse.go @@ -3,6 +3,7 @@ package api import ( "errors" "fmt" + "reflect" "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" @@ -48,6 +49,25 @@ func ValidationErrorResponse(err error) gin.H { } } +func ValidationErrorResponseV2(err error, s interface{}, tagName string) gin.H { + var ves validator.ValidationErrors + var temp []APIValidationError + if errors.As(err, &ves) { + out := make([]APIValidationError, len(ves)) + for i, ve := range ves { + fieldName := ve.Field() + field, _ := reflect.TypeOf(s).FieldByName(fieldName) + tag := field.Tag.Get(tagName) + out[i] = APIValidationError{tag, validationErrorMsg(tag, ve.Param(), ve.ActualTag(), ve.Type().Name())} + } + temp = out + } + return gin.H{ + "message": "Validation error", + "errors": temp, + } +} + func ErrorResponse(err error, msg string) gin.H { return gin.H{ "error": err.Error(), diff --git a/data.ms/VERSION b/data.ms/VERSION old mode 100755 new mode 100644 index ce6a70b..afa2b35 --- a/data.ms/VERSION +++ b/data.ms/VERSION @@ -1 +1 @@ -1.6.0 \ No newline at end of file +1.8.0 \ No newline at end of file diff --git a/data.ms/auth/data.mdb b/data.ms/auth/data.mdb old mode 100755 new mode 100644 index 632246a..527eb7b Binary files a/data.ms/auth/data.mdb and b/data.ms/auth/data.mdb differ diff --git a/data.ms/auth/lock.mdb b/data.ms/auth/lock.mdb old mode 100755 new mode 100644 index d2a6034..a819e1f Binary files a/data.ms/auth/lock.mdb and b/data.ms/auth/lock.mdb differ diff --git a/data.ms/indexes/7cfc824a-b5b6-44e5-98e9-36b251867cac/data.mdb b/data.ms/indexes/7cfc824a-b5b6-44e5-98e9-36b251867cac/data.mdb deleted file mode 100755 index 75eec7f..0000000 Binary files a/data.ms/indexes/7cfc824a-b5b6-44e5-98e9-36b251867cac/data.mdb and /dev/null differ diff --git a/data.ms/indexes/7cfc824a-b5b6-44e5-98e9-36b251867cac/lock.mdb b/data.ms/indexes/7cfc824a-b5b6-44e5-98e9-36b251867cac/lock.mdb deleted file mode 100755 index d263ef7..0000000 Binary files a/data.ms/indexes/7cfc824a-b5b6-44e5-98e9-36b251867cac/lock.mdb and /dev/null differ diff --git a/data.ms/instance-uid b/data.ms/instance-uid old mode 100755 new mode 100644 index f222759..a44139e --- a/data.ms/instance-uid +++ b/data.ms/instance-uid @@ -1 +1 @@ -3db8a6fc-efe2-4e2e-a2ca-2de2e6914f2a \ No newline at end of file +864514bc-7376-4dbe-83ac-1a1c43681252 \ No newline at end of file diff --git a/data.ms/tasks/data.mdb b/data.ms/tasks/data.mdb old mode 100755 new mode 100644 index 821990c..e4ef7d3 Binary files a/data.ms/tasks/data.mdb and b/data.ms/tasks/data.mdb differ diff --git a/data.ms/tasks/lock.mdb b/data.ms/tasks/lock.mdb old mode 100755 new mode 100644 index eb2d077..1db1717 Binary files a/data.ms/tasks/lock.mdb and b/data.ms/tasks/lock.mdb differ diff --git a/db/mock/store.go b/db/mock/store.go index 576bfcc..cf351f7 100755 --- a/db/mock/store.go +++ b/db/mock/store.go @@ -187,6 +187,21 @@ func (mr *MockStoreMockRecorder) GetCountImageByLocation(arg0, arg1 any) *gomock return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCountImageByLocation", reflect.TypeOf((*MockStore)(nil).GetCountImageByLocation), arg0, arg1) } +// GetCountLocations mocks base method. +func (m *MockStore) GetCountLocations(arg0 context.Context, arg1 db.GetCountLocationsParams) (int32, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetCountLocations", arg0, arg1) + ret0, _ := ret[0].(int32) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetCountLocations indicates an expected call of GetCountLocations. +func (mr *MockStoreMockRecorder) GetCountLocations(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCountLocations", reflect.TypeOf((*MockStore)(nil).GetCountLocations), arg0, arg1) +} + // GetImagesByLocation mocks base method. func (m *MockStore) GetImagesByLocation(arg0 context.Context, arg1 db.GetImagesByLocationParams) ([]db.GetImagesByLocationRow, error) { m.ctrl.T.Helper() diff --git a/db/sqlc/db.go b/db/sqlc/db.go index 9959cd0..5b8c8f5 100755 --- a/db/sqlc/db.go +++ b/db/sqlc/db.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.26.0 package db diff --git a/db/sqlc/follow.sql.go b/db/sqlc/follow.sql.go index ded44a0..2970d72 100755 --- a/db/sqlc/follow.sql.go +++ b/db/sqlc/follow.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.26.0 // source: follow.sql package db diff --git a/db/sqlc/helper.go b/db/sqlc/helper.go new file mode 100644 index 0000000..7f45c69 --- /dev/null +++ b/db/sqlc/helper.go @@ -0,0 +1,25 @@ +package db + +import "strings" + +func IsLocationTypeValid(l string) bool { + var validLocationTypes = []LocationType{ + LocationTypeAmusementpark, + LocationTypeBeach, + LocationTypeCulinary, + LocationTypeHikingCamping, + LocationTypeOther, + } + + lTypes := strings.Split(l, ",") + + for _, v := range validLocationTypes { + for _, k := range lTypes { + if v != LocationType(k) { + return false + } + } + } + + return true +} diff --git a/db/sqlc/images.sql.go b/db/sqlc/images.sql.go index cdd981d..d937e16 100755 --- a/db/sqlc/images.sql.go +++ b/db/sqlc/images.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.26.0 // source: images.sql package db diff --git a/db/sqlc/locations.go b/db/sqlc/locations.go index 71136b2..267c353 100755 --- a/db/sqlc/locations.go +++ b/db/sqlc/locations.go @@ -111,6 +111,40 @@ func (q *Queries) GetTopListLocations(ctx context.Context, arg GetTopListLocatio return items, nil } +type GetCountLocationsParams struct { + LocationTypes string `json:"location_type"` + Regency string `json:"regency"` +} + +func (q *Queries) GetCountLocations(ctx context.Context, arg GetCountLocationsParams) (int32, error) { + var count int32 + sqlBuilder := pgq.Select("COUNT(id)").From("locations l") + + if arg.Regency != "" { + regencies := strings.Split(arg.Regency, ",") + sqlBuilder = sqlBuilder.Where(pgq.Eq{"regency_id": regencies}) + } + + if arg.LocationTypes != "" { + locType := strings.Split(arg.LocationTypes, ",") + sqlBuilder = sqlBuilder.Where(pgq.Eq{"l.location_type": locType}) + } + + query, argx, err := sqlBuilder.SQL() + + if err != nil { + return 0, err + } + + err = q.db.QueryRow(ctx, query, argx...).Scan(&count) + if err != nil { + return 0, err + } + + return count, err + +} + type GetListRecentLocationsWithRatingsRow struct { ID int32 `json:"id"` Name string `json:"name"` @@ -125,9 +159,10 @@ type GetListRecentLocationsWithRatingsRow struct { } type GetListRecentLocationsParams struct { - Limit int32 `json:"limit" default:"12"` + Limit uint64 `json:"limit" default:"15"` Regions string `json:"regions" default:""` LocationTypes string `json:"location_type" default:""` + Offset uint64 `json:"offset" default:"0"` } func (q *Queries) GetListRecentLocationsWithRatings(ctx context.Context, arg GetListRecentLocationsParams) ([]GetListRecentLocationsWithRatingsRow, error) { @@ -146,7 +181,8 @@ func (q *Queries) GetListRecentLocationsWithRatings(ctx context.Context, arg Get From("locations l"). Join("regencies re on re.id = l.regency_id"). Join("provinces pr on re.province_id = pr.id"). - Limit(uint64(arg.Limit)) + Limit(arg.Limit). + Offset(arg.Offset) if arg.Regions != "" { region := strings.Split(arg.Regions, ",") diff --git a/db/sqlc/locations.sql.go b/db/sqlc/locations.sql.go index 6700afd..3b17111 100755 --- a/db/sqlc/locations.sql.go +++ b/db/sqlc/locations.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.26.0 // source: locations.sql package db diff --git a/db/sqlc/models.go b/db/sqlc/models.go index 1fece82..5a1e68e 100755 --- a/db/sqlc/models.go +++ b/db/sqlc/models.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.26.0 package db diff --git a/db/sqlc/news_events.sql.go b/db/sqlc/news_events.sql.go index 499319b..c6a2be9 100755 --- a/db/sqlc/news_events.sql.go +++ b/db/sqlc/news_events.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.26.0 // source: news_events.sql package db diff --git a/db/sqlc/provinces.sql.go b/db/sqlc/provinces.sql.go index 909c352..9a8c2f1 100755 --- a/db/sqlc/provinces.sql.go +++ b/db/sqlc/provinces.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.26.0 // source: provinces.sql package db diff --git a/db/sqlc/querier.go b/db/sqlc/querier.go index 88fafcb..cd78324 100755 --- a/db/sqlc/querier.go +++ b/db/sqlc/querier.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.26.0 package db diff --git a/db/sqlc/regencies.sql.go b/db/sqlc/regencies.sql.go index 2a50faf..6cc394c 100755 --- a/db/sqlc/regencies.sql.go +++ b/db/sqlc/regencies.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.26.0 // source: regencies.sql package db diff --git a/db/sqlc/regions.sql.go b/db/sqlc/regions.sql.go index b7fe525..1d1fbc6 100755 --- a/db/sqlc/regions.sql.go +++ b/db/sqlc/regions.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.26.0 // source: regions.sql package db diff --git a/db/sqlc/reviews.sql.go b/db/sqlc/reviews.sql.go index 9ab7ca9..b992ca5 100755 --- a/db/sqlc/reviews.sql.go +++ b/db/sqlc/reviews.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.26.0 // source: reviews.sql package db diff --git a/db/sqlc/sessions.sql.go b/db/sqlc/sessions.sql.go index da04aa5..55acff7 100755 --- a/db/sqlc/sessions.sql.go +++ b/db/sqlc/sessions.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.26.0 // source: sessions.sql package db diff --git a/db/sqlc/store.go b/db/sqlc/store.go index a4bcd57..d8cb644 100755 --- a/db/sqlc/store.go +++ b/db/sqlc/store.go @@ -22,6 +22,7 @@ type Store interface { CreateLocationTx(ctx context.Context, arg CreateLocationTxParams) error GetNewsEventsList(ctx context.Context, arg GetNewsEventsListParams) ([]NewsEventRow, error) GetListRecentLocationsWithRatings(ctx context.Context, arg GetListRecentLocationsParams) ([]GetListRecentLocationsWithRatingsRow, error) + GetCountLocations(ctx context.Context, arg GetCountLocationsParams) (int32, error) } type SQLStore struct { diff --git a/db/sqlc/users.sql.go b/db/sqlc/users.sql.go index 6455940..096ee98 100755 --- a/db/sqlc/users.sql.go +++ b/db/sqlc/users.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.25.0 +// sqlc v1.26.0 // source: users.sql package db diff --git a/util/cursor.go b/util/cursor.go new file mode 100644 index 0000000..bad80c4 --- /dev/null +++ b/util/cursor.go @@ -0,0 +1,54 @@ +package util + +import ( + "encoding/base64" + "encoding/json" + "time" +) + +type PaginationInfo struct { + NextCursor string `json:"next_cursor"` + PrevCursor string `json:"prev_cursor"` +} + +type Cursor map[string]interface{} + +func CreateCursor(id string, createdAt time.Time, pointsNext bool) Cursor { + return Cursor{ + "id": id, + "created_at": createdAt, + "points_next": pointsNext, + } +} + +func GeneratePager(next Cursor, prev Cursor) PaginationInfo { + return PaginationInfo{ + NextCursor: encodeCursor(next), + PrevCursor: encodeCursor(prev), + } +} + +func encodeCursor(cursor Cursor) string { + if len(cursor) == 0 { + return "" + } + serializedCursor, err := json.Marshal(cursor) + if err != nil { + return "" + } + encodedCursor := base64.StdEncoding.EncodeToString(serializedCursor) + return encodedCursor +} + +func DecodeCursor(cursor string) (Cursor, error) { + decodedCursor, err := base64.StdEncoding.DecodeString(cursor) + if err != nil { + return nil, err + } + + var cur Cursor + if err := json.Unmarshal(decodedCursor, &cur); err != nil { + return nil, err + } + return cur, nil +}