From cf14079f1f048191644b5c774564161277623aa1 Mon Sep 17 00:00:00 2001 From: Tigor Hutasuhut Date: Thu, 15 Aug 2024 10:23:56 +0700 Subject: [PATCH] refactor: api now uses it's own request type and handlers will now handles the conversion of the request to the api request type --- go/api/api.go | 10 ++- go/api/devices_list.go | 62 +++++++------- go/converts/{converter.go => device.go} | 104 ++++++++---------------- go/converts/utils.go | 80 ++++++++++++++++++ go/server/device_handlers.go | 14 +++- schemas/proto/device/v1/device.proto | 17 ---- schemas/proto/device/v1/get.proto | 2 +- schemas/proto/device/v1/list.proto | 9 +- schemas/proto/device/v1/types.proto | 22 +++++ 9 files changed, 187 insertions(+), 133 deletions(-) rename go/converts/{converter.go => device.go} (50%) create mode 100644 go/converts/utils.go create mode 100644 schemas/proto/device/v1/types.proto diff --git a/go/api/api.go b/go/api/api.go index 94773e3..3b80fee 100644 --- a/go/api/api.go +++ b/go/api/api.go @@ -5,11 +5,8 @@ import ( "sync" "github.com/stephenafamo/bob" - "github.com/tigorlazuardi/bluemage/go/gen/converter" ) -var convert converter.DeviceConverterImpl - type API struct { mu sync.Mutex Executor bob.Executor @@ -21,3 +18,10 @@ func (api *API) lockf(f func()) { defer api.mu.Unlock() f() } + +type Sort string + +const ( + SortAsc Sort = "asc" + SortDesc Sort = "desc" +) diff --git a/go/api/devices_list.go b/go/api/devices_list.go index 2aeb6bf..ac7fd8c 100644 --- a/go/api/devices_list.go +++ b/go/api/devices_list.go @@ -1,9 +1,6 @@ package api import ( - "strings" - - device "github.com/tigorlazuardi/bluemage/go/gen/proto/device/v1" "github.com/tigorlazuardi/bluemage/go/pkg/errs" "golang.org/x/net/context" @@ -12,19 +9,30 @@ import ( . "github.com/tigorlazuardi/bluemage/go/gen/jet/table" ) -func listDevicesRequestSelectStatement(req *device.ListDevicesRequest) SelectStatement { +type ListDevicesRequest struct { + Search string + Disabled *bool + Limit int64 + Offset int64 + OrderBy string + Sort Sort +} + +func (request ListDevicesRequest) Statement() SelectStatement { cond := Bool(true) - switch req.Disabled { - case device.DisabledFilter_DISABLED_FILTER_TRUE: - cond.AND(Devices.Disabled.EQ(Int(1))) - case device.DisabledFilter_DISABLED_FILTER_FALSE: - cond.AND(Devices.Disabled.EQ(Int(0))) + if d := request.Disabled; d != nil { + disabled := *d + if disabled { + cond.AND(Devices.Disabled.EQ(Int(1))) + } else { + cond.AND(Devices.Disabled.EQ(Int(0))) + } } - if req.Search != "" { + if request.Search != "" { cond.AND( - Devices.Name.LIKE(String("%" + req.Search + "%")). - OR(Devices.Slug.LIKE(String("%" + req.Search + "%"))), + Devices.Name.LIKE(String("%" + request.Search + "%")). + OR(Devices.Slug.LIKE(String("%" + request.Search + "%"))), ) } @@ -32,45 +40,35 @@ func listDevicesRequestSelectStatement(req *device.ListDevicesRequest) SelectSta FROM(Devices). WHERE(cond) - if req.Limit > 0 { - stmt.LIMIT(int64(req.Limit)) + if request.Limit > 0 { + stmt.LIMIT(request.Limit) } - if req.Offset > 0 { - stmt.OFFSET(int64(req.Offset)) + if request.Offset > 0 { + stmt.OFFSET(request.Offset) } - - if req.OrderBy == device.OrderBy_ORDER_BY_UNSPECIFIED { + if request.OrderBy == "" { return stmt.ORDER_BY(Devices.CreatedAt.DESC()) } - orderByField, _ := strings.CutPrefix(device.OrderBy_name[int32(req.OrderBy)], "ORDER_BY_") - orderByField = strings.ToLower(orderByField) - - orderBy := StringColumn(orderByField) - - if req.Sort == device.Sort_SORT_DESCENDING { + orderBy := StringColumn(request.OrderBy) + if request.Sort == SortDesc { return stmt.ORDER_BY(orderBy.DESC()) } else { return stmt.ORDER_BY(orderBy.ASC()) } } -func (api *API) DevicesList(ctx context.Context, req *device.ListDevicesRequest) (resp *device.ListDevicesResponse, err error) { +func (api *API) DevicesList(ctx context.Context, req ListDevicesRequest) (resp []model.Devices, err error) { ctx, span := tracer.Start(ctx, "DevicesList") defer span.End() - resp = &device.ListDevicesResponse{} - stmt := listDevicesRequestSelectStatement(req) - var out []model.Devices - if err := stmt.QueryContext(ctx, api.DB, &out); err != nil { + stmt := req.Statement() + if err := stmt.QueryContext(ctx, api.DB, &resp); err != nil { return resp, errs.Wrapw(err, "failed to list devices", "request", req, "query", stmt.DebugSql(), ) } - for _, result := range out { - resp.Devices = append(resp.Devices, convert.JetModelDeviceToGetDeviceResponse(result)) - } return resp, err } diff --git a/go/converts/converter.go b/go/converts/device.go similarity index 50% rename from go/converts/converter.go rename to go/converts/device.go index ee1bb8b..22136f2 100644 --- a/go/converts/converter.go +++ b/go/converts/device.go @@ -1,7 +1,9 @@ package converts import ( - "github.com/aarondl/opt/omit" + "strings" + + "github.com/tigorlazuardi/bluemage/go/api" "github.com/tigorlazuardi/bluemage/go/gen/jet/model" "github.com/tigorlazuardi/bluemage/go/gen/models" device "github.com/tigorlazuardi/bluemage/go/gen/proto/device/v1" @@ -24,6 +26,9 @@ import ( // goverter:extend Int64ToOmitInt64 // goverter:extend Float64ToOmitFloat64 // goverter:extend StringToOmitString +// goverter:extend DeviceDisabledFilterToPtrBool +// goverter:extend DeviceOrderByToString +// goverter:extend DeviceSortToAPISort type DeviceConverter interface { // goverter:ignore CreatedAt UpdatedAt // goverter:map Nsfw NSFW @@ -32,86 +37,41 @@ type DeviceConverter interface { ModelsDeviceToCreateDeviceResponse(*models.Device) *device.CreateDeviceResponse // goverter:ignore state sizeCache unknownFields // goverter:useZeroValueOnPointerInconsistency - JetModelDeviceToGetDeviceResponse(model.Devices) *device.GetDeviceResponse + JetModelDeviceToProtoDevice(model.Devices) *device.Device + + // goverter:useZeroValueOnPointerInconsistency + ListDevicesRequestToAPIListDevicesRequest(*device.ListDevicesRequest) api.ListDevicesRequest // goverter:ignore Slug SingleFolderMode CreatedAt UpdatedAt // goverter:map Nsfw NSFW DeviceSetterProtoToModelsDeviceSetter(*device.DeviceSetter) *models.DeviceSetter } -func BoolToInt8(b bool) int8 { - if b { - return 1 +func DeviceDisabledFilterToPtrBool(f device.DisabledFilter) *bool { + switch f { + case device.DisabledFilter_DISABLED_FILTER_TRUE: + b := true + return &b + case device.DisabledFilter_DISABLED_FILTER_FALSE: + b := false + return &b + default: + return nil } - return 0 } -func PtrBoolToOmitInt8(b *bool) omit.Val[int8] { - if b == nil { - return omit.Val[int8]{} +func DeviceOrderByToString(order device.OrderBy) string { + if order == device.OrderBy_ORDER_BY_UNSPECIFIED { + return "" } - v := *b - if v { - return omit.From(int8(1)) + field, _ := strings.CutPrefix(device.OrderBy_name[int32(order)], "ORDER_BY_") + field = strings.ToLower(field) + return field +} + +func DeviceSortToAPISort(sort device.Sort) api.Sort { + if sort == device.Sort_SORT_DESCENDING { + return api.SortDesc } - return omit.From(int8(0)) -} - -func PtrStringToOmitString(s *string) omit.Val[string] { - return omit.FromPtr(s) -} - -func StringToOmitString(s string) omit.Val[string] { - return omit.From(s) -} - -func PtrFloat64ToOmitFloat64(f *float64) omit.Val[float64] { - return omit.FromPtr(f) -} - -func Float64ToOmitFloat64(f float64) omit.Val[float64] { - return omit.From(f) -} - -func PtrIntToOmitInt(i *int) omit.Val[int] { - return omit.FromPtr(i) -} - -func IntToOmitInt(i int) omit.Val[int] { - return omit.From(i) -} - -func PtrInt8ToOmitInt8(i *int8) omit.Val[int8] { - return omit.FromPtr(i) -} - -func Int8ToOmitInt8(i int8) omit.Val[int8] { - return omit.From(i) -} - -func PtrInt32ToOmitInt32(i *int32) omit.Val[int32] { - return omit.FromPtr(i) -} - -func Int32ToOmitInt32(i int32) omit.Val[int32] { - return omit.From(i) -} - -func PtrInt64ToOmitInt64(i *int64) omit.Val[int64] { - return omit.FromPtr(i) -} - -func Int64ToOmitInt64(i int64) omit.Val[int64] { - return omit.From(i) -} - -func BoolToOmitInt8(b bool) omit.Val[int8] { - if b { - return omit.From(int8(1)) - } - return omit.From(int8(0)) -} - -func Int8ToBool(i int8) bool { - return i > 0 + return api.SortDesc } diff --git a/go/converts/utils.go b/go/converts/utils.go new file mode 100644 index 0000000..500c339 --- /dev/null +++ b/go/converts/utils.go @@ -0,0 +1,80 @@ +package converts + +import "github.com/aarondl/opt/omit" + +func BoolToInt8(b bool) int8 { + if b { + return 1 + } + return 0 +} + +func PtrBoolToOmitInt8(b *bool) omit.Val[int8] { + if b == nil { + return omit.Val[int8]{} + } + v := *b + if v { + return omit.From(int8(1)) + } + return omit.From(int8(0)) +} + +func PtrStringToOmitString(s *string) omit.Val[string] { + return omit.FromPtr(s) +} + +func StringToOmitString(s string) omit.Val[string] { + return omit.From(s) +} + +func PtrFloat64ToOmitFloat64(f *float64) omit.Val[float64] { + return omit.FromPtr(f) +} + +func Float64ToOmitFloat64(f float64) omit.Val[float64] { + return omit.From(f) +} + +func PtrIntToOmitInt(i *int) omit.Val[int] { + return omit.FromPtr(i) +} + +func IntToOmitInt(i int) omit.Val[int] { + return omit.From(i) +} + +func PtrInt8ToOmitInt8(i *int8) omit.Val[int8] { + return omit.FromPtr(i) +} + +func Int8ToOmitInt8(i int8) omit.Val[int8] { + return omit.From(i) +} + +func PtrInt32ToOmitInt32(i *int32) omit.Val[int32] { + return omit.FromPtr(i) +} + +func Int32ToOmitInt32(i int32) omit.Val[int32] { + return omit.From(i) +} + +func PtrInt64ToOmitInt64(i *int64) omit.Val[int64] { + return omit.FromPtr(i) +} + +func Int64ToOmitInt64(i int64) omit.Val[int64] { + return omit.From(i) +} + +func BoolToOmitInt8(b bool) omit.Val[int8] { + if b { + return omit.From(int8(1)) + } + return omit.From(int8(0)) +} + +func Int8ToBool(i int8) bool { + return i > 0 +} diff --git a/go/server/device_handlers.go b/go/server/device_handlers.go index 46d9ca9..b9552b3 100644 --- a/go/server/device_handlers.go +++ b/go/server/device_handlers.go @@ -39,16 +39,24 @@ func (d *DeviceHandler) GetDevice(ctx context.Context, request *connect.Request[ return nil, errs.IntoConnectError(err) } - devResp := deviceConvert.JetModelDeviceToGetDeviceResponse(dev) - return connect.NewResponse(devResp), nil + data := deviceConvert.JetModelDeviceToProtoDevice(dev) + resp := &device.GetDeviceResponse{ + Device: data, + } + return connect.NewResponse(resp), nil } // ListDevices implements v1connect.DeviceServiceHandler. func (d *DeviceHandler) ListDevices(ctx context.Context, request *connect.Request[device.ListDevicesRequest]) (*connect.Response[device.ListDevicesResponse], error) { - resp, err := d.API.DevicesList(ctx, request.Msg) + listRequest := deviceConvert.ListDevicesRequestToAPIListDevicesRequest(request.Msg) + devices, err := d.API.DevicesList(ctx, listRequest) if err != nil { return nil, errs.IntoConnectError(err) } + resp := &device.ListDevicesResponse{} + for _, device := range devices { + resp.Devices = append(resp.Devices, deviceConvert.JetModelDeviceToProtoDevice(device)) + } return connect.NewResponse(resp), nil } diff --git a/schemas/proto/device/v1/device.proto b/schemas/proto/device/v1/device.proto index 4ba968f..1e8b365 100644 --- a/schemas/proto/device/v1/device.proto +++ b/schemas/proto/device/v1/device.proto @@ -38,20 +38,3 @@ service DeviceService { // CountDevices count the number of devices. rpc CountDevices(CountDevicesRequest) returns (CountDevicesResponse) {} } - -message Device { - string slug = 1; - bool disabled = 2; - string name = 3; - double resolution_x = 4; - double resolution_y = 5; - double aspect_ratio_tolerance = 6; - int32 min_x = 7; - int32 min_y = 8; - int32 max_x = 9; - int32 max_y = 10; - bool nsfw = 11; - bool single_folder_mode = 12; - int64 created_at = 13; - int64 updated_at = 14; -} diff --git a/schemas/proto/device/v1/get.proto b/schemas/proto/device/v1/get.proto index 18982c9..6043194 100644 --- a/schemas/proto/device/v1/get.proto +++ b/schemas/proto/device/v1/get.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package device.v1; import "buf/validate/validate.proto"; -import "device/v1/device.proto"; +import "device/v1/types.proto"; option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/device/v1"; diff --git a/schemas/proto/device/v1/list.proto b/schemas/proto/device/v1/list.proto index 64e036b..aca676a 100644 --- a/schemas/proto/device/v1/list.proto +++ b/schemas/proto/device/v1/list.proto @@ -2,8 +2,7 @@ syntax = "proto3"; package device.v1; -// import "buf/validate/validate.proto"; -import "device/v1/get.proto"; +import "device/v1/types.proto"; option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/device/v1"; @@ -28,12 +27,12 @@ message ListDevicesRequest { // if value is 0 or not given, limit is set to 25. // // if limit is higher than 100, it is clamped to 100. - uint32 limit = 3; + int64 limit = 3; // offset for the given data. // // If offset is 0 or not given, the query begins from start. - uint32 offset = 4; + int64 offset = 4; // order_by is the field to order the devices by. // @@ -47,7 +46,7 @@ message ListDevicesRequest { } message ListDevicesResponse { - repeated GetDeviceResponse devices = 1; + repeated Device devices = 1; } enum DisabledFilter { diff --git a/schemas/proto/device/v1/types.proto b/schemas/proto/device/v1/types.proto new file mode 100644 index 0000000..369a20f --- /dev/null +++ b/schemas/proto/device/v1/types.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +package device.v1; + +option go_package = "github.com/tigorlazuardi/bluemage/go/gen/proto/device/v1"; + +message Device { + string slug = 1; + bool disabled = 2; + string name = 3; + double resolution_x = 4; + double resolution_y = 5; + double aspect_ratio_tolerance = 6; + int32 min_x = 7; + int32 min_y = 8; + int32 max_x = 9; + int32 max_y = 10; + bool nsfw = 11; + bool single_folder_mode = 12; + int64 created_at = 13; + int64 updated_at = 14; +}