feat: it works
This commit is contained in:
parent
6302dd62d6
commit
778d5ef146
25 changed files with 638 additions and 106 deletions
|
|
@ -1,6 +1,8 @@
|
|||
package ds
|
||||
|
||||
import "github.com/google/uuid"
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Status string
|
||||
|
||||
|
|
@ -15,3 +17,9 @@ type Station struct {
|
|||
Slug string
|
||||
Status Status
|
||||
}
|
||||
|
||||
type Satellite struct {
|
||||
ID uuid.UUID
|
||||
DisplayName string
|
||||
Status Status
|
||||
}
|
||||
25
internal/pkg/errcodes/errcodes.go
Normal file
25
internal/pkg/errcodes/errcodes.go
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package errcodes
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ErrorCode struct {
|
||||
StatusCode int
|
||||
Message string
|
||||
Details string
|
||||
}
|
||||
|
||||
var errorCodeCounter int32
|
||||
|
||||
func New(statusCode int, message string, details ...string) *ErrorCode {
|
||||
return &ErrorCode{
|
||||
StatusCode: statusCode,
|
||||
Message: message,
|
||||
Details: strings.Join(details, " "),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *ErrorCode) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
23
internal/repository/config.go
Normal file
23
internal/repository/config.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
env "github.com/caarlos0/env/v11"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
ConnStr string `env:"CONNSTR" envDefault:"postgres://gsn:gsn@localhost:5432/gsn?sslmode=disable"`
|
||||
}
|
||||
|
||||
func NewConfig(servicePrefix string) (*Config, error) {
|
||||
cfg := &Config{}
|
||||
|
||||
if err := env.ParseWithOptions(cfg, env.Options{
|
||||
PrefixTagName: fmt.Sprintf("%s_REPOSITORY_", servicePrefix),
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
|
@ -1,4 +1,3 @@
|
|||
-- name: GetStationByID :one
|
||||
-- name: GetSatellites :many
|
||||
select *
|
||||
from stations
|
||||
where id = @id;
|
||||
from satellites;
|
||||
|
|
@ -3,24 +3,23 @@ package repository
|
|||
import (
|
||||
"context"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/ds"
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/repository/sqlc"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
type Repository struct {
|
||||
queries *sqlc.Queries
|
||||
cfg *Config
|
||||
}
|
||||
|
||||
func (r *Repository) GetStationByID(ctx context.Context, ID uuid.UUID) (ds.Station, error) {
|
||||
ret, err := r.queries.GetStationByID(ctx, UUIDToPg(ID))
|
||||
func New(cfg *Config) (*Repository, error) {
|
||||
conn, err := pgx.Connect(context.Background(), cfg.ConnStr)
|
||||
if err != nil {
|
||||
return ds.Station{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ds.Station{
|
||||
ID: PGToUUID(ret.ID),
|
||||
Slug: ret.Slug,
|
||||
Status: ds.Status(ret.Status),
|
||||
return &Repository{
|
||||
queries: sqlc.New(conn),
|
||||
cfg: cfg,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
27
internal/repository/satellites.go
Normal file
27
internal/repository/satellites.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/ds"
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/errcodes"
|
||||
)
|
||||
|
||||
func (r *Repository) GetSatellites(ctx context.Context) ([]ds.Satellite, error) {
|
||||
satellites, err := r.queries.GetSatellites(ctx)
|
||||
if err != nil {
|
||||
return nil, errcodes.New(http.StatusInternalServerError, "failed to get satellites", err.Error())
|
||||
}
|
||||
|
||||
ret := make([]ds.Satellite, 0, len(satellites))
|
||||
for _, val := range satellites {
|
||||
ret = append(ret, ds.Satellite{
|
||||
ID: PGToUUID(val.ID),
|
||||
DisplayName: val.DisplayName,
|
||||
Status: ds.Status(val.Status),
|
||||
})
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
|
@ -7,19 +7,29 @@ package sqlc
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const getStationByID = `-- name: GetStationByID :one
|
||||
select id, slug, status
|
||||
from stations
|
||||
where id = $1
|
||||
const getSatellites = `-- name: GetSatellites :many
|
||||
select id, display_name, status
|
||||
from satellites
|
||||
`
|
||||
|
||||
func (q *Queries) GetStationByID(ctx context.Context, id pgtype.UUID) (Station, error) {
|
||||
row := q.db.QueryRow(ctx, getStationByID, id)
|
||||
var i Station
|
||||
err := row.Scan(&i.ID, &i.Slug, &i.Status)
|
||||
return i, err
|
||||
func (q *Queries) GetSatellites(ctx context.Context) ([]Satellite, error) {
|
||||
rows, err := q.db.Query(ctx, getSatellites)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []Satellite
|
||||
for rows.Next() {
|
||||
var i Satellite
|
||||
if err := rows.Scan(&i.ID, &i.DisplayName, &i.Status); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
|
|
|||
12
internal/service/deps.go
Normal file
12
internal/service/deps.go
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/ds"
|
||||
)
|
||||
|
||||
//go:generate mockgen -source=deps.go -destination=deps_mock.go -package=service
|
||||
type Repository interface {
|
||||
GetSatellites(ctx context.Context) ([]ds.Satellite, error)
|
||||
}
|
||||
51
internal/service/deps_mock.go
Normal file
51
internal/service/deps_mock.go
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: deps.go
|
||||
|
||||
// Package service is a generated GoMock package.
|
||||
package service
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
ds "git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/ds"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// GetSatellites mocks base method.
|
||||
func (m *MockRepository) GetSatellites(ctx context.Context) ([]ds.Satellite, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetSatellites", ctx)
|
||||
ret0, _ := ret[0].([]ds.Satellite)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetSatellites indicates an expected call of GetSatellites.
|
||||
func (mr *MockRepositoryMockRecorder) GetSatellites(ctx interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSatellites", reflect.TypeOf((*MockRepository)(nil).GetSatellites), ctx)
|
||||
}
|
||||
11
internal/service/satellites.go
Normal file
11
internal/service/satellites.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/ds"
|
||||
)
|
||||
|
||||
func (s *Service) GetSatellites(ctx context.Context) ([]ds.Satellite, error) {
|
||||
return s.repo.GetSatellites(ctx)
|
||||
}
|
||||
66
internal/service/satellites_test.go
Normal file
66
internal/service/satellites_test.go
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/ds"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func Test_GetSatellites(t *testing.T) {
|
||||
suite := NewSuite(t)
|
||||
|
||||
var (
|
||||
commonSatelliteID = uuid.New()
|
||||
commonDisplayName = "test"
|
||||
commonStatus = ds.StatusActive
|
||||
)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
mock func()
|
||||
expected []ds.Satellite
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "success",
|
||||
mock: func() {
|
||||
suite.mockRepo.EXPECT().GetSatellites(gomock.Any()).Return([]ds.Satellite{
|
||||
{
|
||||
ID: commonSatelliteID,
|
||||
DisplayName: commonDisplayName,
|
||||
Status: commonStatus,
|
||||
},
|
||||
}, nil)
|
||||
},
|
||||
expected: []ds.Satellite{
|
||||
{
|
||||
ID: commonSatelliteID,
|
||||
DisplayName: commonDisplayName,
|
||||
Status: commonStatus,
|
||||
},
|
||||
},
|
||||
wantErr: nil,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if tt.mock != nil {
|
||||
tt.mock()
|
||||
}
|
||||
|
||||
result, err := suite.svc.GetSatellites(context.Background())
|
||||
if tt.wantErr != nil {
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
require.True(t, reflect.DeepEqual(tt.expected, result))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
11
internal/service/service.go
Normal file
11
internal/service/service.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package service
|
||||
|
||||
type Service struct {
|
||||
repo Repository
|
||||
}
|
||||
|
||||
func New(repo Repository) *Service {
|
||||
return &Service{
|
||||
repo: repo,
|
||||
}
|
||||
}
|
||||
27
internal/service/service_test.go
Normal file
27
internal/service/service_test.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
type TestSuite struct {
|
||||
svc *Service
|
||||
mockRepo *MockRepository
|
||||
}
|
||||
|
||||
func NewSuite(t *testing.T) *TestSuite {
|
||||
t.Helper()
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
mockRepo := NewMockRepository(ctrl)
|
||||
|
||||
svc := New(mockRepo)
|
||||
|
||||
return &TestSuite{
|
||||
svc: svc,
|
||||
mockRepo: mockRepo,
|
||||
}
|
||||
}
|
||||
23
internal/transport/rest/config.go
Normal file
23
internal/transport/rest/config.go
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
env "github.com/caarlos0/env/v11"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Port int `env:"PORT" envDefault:"8080"`
|
||||
}
|
||||
|
||||
func NewConfig(servicePrefix string) (*Config, error) {
|
||||
cfg := &Config{}
|
||||
|
||||
if err := env.ParseWithOptions(cfg, env.Options{
|
||||
PrefixTagName: fmt.Sprintf("%s_REST_", servicePrefix),
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
package rest
|
||||
|
||||
type Service interface {
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
api "git.intra.yksa.space/gsn/gsn-proxy/pkg/rest"
|
||||
)
|
||||
|
||||
var (
|
||||
_ api.Handler = (*Handler)(nil)
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
svc Service
|
||||
}
|
||||
|
||||
func (h *Handler) GetSatellites(ctx context.Context) (*api.GetSatellitesOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) GetStations(ctx context.Context) (*api.GetStationsOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) GetSubscriptions(ctx context.Context) (*api.GetSubscriptionsOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) SubscribeSatellite(ctx context.Context, req *api.SubscribeSatelliteReq) (*api.SubscribeSatelliteOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) SubscribeStation(ctx context.Context, req *api.SubscribeStationReq) (*api.SubscribeStationOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) Unsubscribe(ctx context.Context, params api.UnsubscribeParams) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) NewError(ctx context.Context, err error) *api.ErrorStatusCode {
|
||||
return nil
|
||||
}
|
||||
11
internal/transport/rest/handler/deps.go
Normal file
11
internal/transport/rest/handler/deps.go
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/ds"
|
||||
)
|
||||
|
||||
type Service interface {
|
||||
GetSatellites(ctx context.Context) ([]ds.Satellite, error)
|
||||
}
|
||||
89
internal/transport/rest/handler/handler.go
Normal file
89
internal/transport/rest/handler/handler.go
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"git.intra.yksa.space/gsn/gsn-proxy/internal/pkg/errcodes"
|
||||
api "git.intra.yksa.space/gsn/gsn-proxy/pkg/rest"
|
||||
)
|
||||
|
||||
var (
|
||||
_ api.Handler = (*Handler)(nil)
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
svc Service
|
||||
}
|
||||
|
||||
func New(svc Service) *Handler {
|
||||
return &Handler{
|
||||
svc: svc,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) GetSatellites(ctx context.Context) (*api.GetSatellitesOK, error) {
|
||||
satellites, err := h.svc.GetSatellites(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := make([]api.GetSatellitesOKSatellitesItem, 0, len(satellites))
|
||||
for _, val := range satellites {
|
||||
ret = append(ret, api.GetSatellitesOKSatellitesItem{
|
||||
ID: val.ID,
|
||||
DisplayName: val.DisplayName,
|
||||
Status: api.GetSatellitesOKSatellitesItemStatus(val.Status),
|
||||
})
|
||||
}
|
||||
|
||||
return &api.GetSatellitesOK{
|
||||
Satellites: ret,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *Handler) GetStations(ctx context.Context) (*api.GetStationsOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) GetSubscriptions(ctx context.Context) (*api.GetSubscriptionsOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) SubscribeSatellite(ctx context.Context, req *api.SubscribeSatelliteReq) (*api.SubscribeSatelliteOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) SubscribeStation(ctx context.Context, req *api.SubscribeStationReq) (*api.SubscribeStationOK, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (h *Handler) Unsubscribe(ctx context.Context, params api.UnsubscribeParams) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Handler) NewError(ctx context.Context, err error) *api.ErrorStatusCode {
|
||||
if errcode, ok := err.(*errcodes.ErrorCode); ok {
|
||||
resp := api.Error{
|
||||
Message: errcode.Message,
|
||||
}
|
||||
|
||||
if errcode.Details != "" {
|
||||
resp.Details = api.NewOptString(errcode.Details)
|
||||
}
|
||||
|
||||
return &api.ErrorStatusCode{
|
||||
StatusCode: errcode.StatusCode,
|
||||
Response: resp,
|
||||
}
|
||||
}
|
||||
|
||||
return &api.ErrorStatusCode{
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
Response: api.Error{
|
||||
Message: fmt.Sprintf("undefined internal error"),
|
||||
Details: api.NewOptString(err.Error()),
|
||||
},
|
||||
}
|
||||
}
|
||||
33
internal/transport/rest/transport.go
Normal file
33
internal/transport/rest/transport.go
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package rest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
handler "git.intra.yksa.space/gsn/gsn-proxy/internal/transport/rest/handler"
|
||||
api "git.intra.yksa.space/gsn/gsn-proxy/pkg/rest"
|
||||
)
|
||||
|
||||
type Transport struct {
|
||||
cfg *Config
|
||||
srv *api.Server
|
||||
}
|
||||
|
||||
func New(handler *handler.Handler, cfg *Config) (*Transport, error) {
|
||||
srv, err := api.NewServer(handler)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Transport{
|
||||
srv: srv,
|
||||
cfg: cfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *Transport) Run() {
|
||||
if err := http.ListenAndServe(fmt.Sprintf(":%d", t.cfg.Port), t.srv); err != nil {
|
||||
log.Panic(err)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue