diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..73f69e0
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
+# Editor-based HTTP Client requests
+/httpRequests/
diff --git a/.idea/go-hexagonal_http_api-course.iml b/.idea/go-hexagonal_http_api-course.iml
new file mode 100644
index 0000000..5e764c4
--- /dev/null
+++ b/.idea/go-hexagonal_http_api-course.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..d247213
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/04-03-command-bus/cmd/api/bootstrap/boostrap.go b/04-03-command-bus/cmd/api/bootstrap/boostrap.go
index ae12dad..5c11596 100644
--- a/04-03-command-bus/cmd/api/bootstrap/boostrap.go
+++ b/04-03-command-bus/cmd/api/bootstrap/boostrap.go
@@ -3,6 +3,7 @@ package bootstrap
import (
"database/sql"
"fmt"
+ "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal/fetching"
"github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal/creating"
"github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal/platform/bus/inmemory"
@@ -30,16 +31,20 @@ func Run() error {
}
var (
- commandBus = inmemory.NewCommandBus()
+ bus = inmemory.NewCommandBus()
)
courseRepository := mysql.NewCourseRepository(db)
creatingCourseService := creating.NewCourseService(courseRepository)
+ fetchingCourseService := fetching.NewCourseFetchingService(courseRepository)
createCourseCommandHandler := creating.NewCourseCommandHandler(creatingCourseService)
- commandBus.Register(creating.CourseCommandType, createCourseCommandHandler)
+ fetchingCourseQueryHandler := fetching.NewCourseQueryHandler(fetchingCourseService)
- srv := server.New(host, port, commandBus)
+ bus.RegisterCommandHandler(creating.CourseCommandType, createCourseCommandHandler)
+ bus.RegisterQueryHandler(fetching.CourseQueryType, fetchingCourseQueryHandler)
+
+ srv := server.New(host, port, bus)
return srv.Run()
}
diff --git a/04-03-command-bus/internal/course.go b/04-03-command-bus/internal/course.go
index 2e98d82..cc8b397 100644
--- a/04-03-command-bus/internal/course.go
+++ b/04-03-command-bus/internal/course.go
@@ -87,6 +87,7 @@ type Course struct {
// CourseRepository defines the expected behaviour from a course storage.
type CourseRepository interface {
Save(ctx context.Context, course Course) error
+ GetAll(ctx context.Context) ([]Course, error)
}
//go:generate mockery --case=snake --outpkg=storagemocks --output=platform/storage/storagemocks --name=CourseRepository
diff --git a/04-03-command-bus/internal/creating/command.go b/04-03-command-bus/internal/creating/command.go
index 0c16431..0b7cd76 100644
--- a/04-03-command-bus/internal/creating/command.go
+++ b/04-03-command-bus/internal/creating/command.go
@@ -4,12 +4,12 @@ import (
"context"
"errors"
- "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/command"
+ "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/bus"
)
-const CourseCommandType command.Type = "command.creating.course"
+const CourseCommandType bus.Type = "bus.creating.course"
-// CourseCommand is the command dispatched to create a new course.
+// CourseCommand is the bus dispatched to create a new course.
type CourseCommand struct {
id string
name string
@@ -25,11 +25,11 @@ func NewCourseCommand(id, name, duration string) CourseCommand {
}
}
-func (c CourseCommand) Type() command.Type {
+func (c CourseCommand) Type() bus.Type {
return CourseCommandType
}
-// CourseCommandHandler is the command handler
+// CourseCommandHandler is the bus handler
// responsible for creating courses.
type CourseCommandHandler struct {
service CourseService
@@ -42,11 +42,11 @@ func NewCourseCommandHandler(service CourseService) CourseCommandHandler {
}
}
-// Handle implements the command.Handler interface.
-func (h CourseCommandHandler) Handle(ctx context.Context, cmd command.Command) error {
+// Handle implements the bus.CommandHandler interface.
+func (h CourseCommandHandler) Handle(ctx context.Context, cmd bus.Command) error {
createCourseCmd, ok := cmd.(CourseCommand)
if !ok {
- return errors.New("unexpected command")
+ return errors.New("unexpected bus")
}
return h.service.CreateCourse(
diff --git a/04-03-command-bus/internal/creating/service.go b/04-03-command-bus/internal/creating/service.go
index 60a7b35..4ae999b 100644
--- a/04-03-command-bus/internal/creating/service.go
+++ b/04-03-command-bus/internal/creating/service.go
@@ -27,3 +27,4 @@ func (s CourseService) CreateCourse(ctx context.Context, id, name, duration stri
}
return s.courseRepository.Save(ctx, course)
}
+
diff --git a/04-03-command-bus/internal/fetching/query.go b/04-03-command-bus/internal/fetching/query.go
new file mode 100644
index 0000000..d20845f
--- /dev/null
+++ b/04-03-command-bus/internal/fetching/query.go
@@ -0,0 +1,45 @@
+package fetching
+
+import (
+ "context"
+ "errors"
+ "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/bus"
+)
+
+const CourseQueryType bus.Type = "bus.fetching.courses"
+
+// CourseQuery is the bus dispatched to create a new course.
+type CourseQuery struct {
+}
+
+// NewFetchCourseQuery creates a new CourseQuery.
+func NewFetchCourseQuery() CourseQuery {
+ return CourseQuery{}
+}
+
+func (c CourseQuery) Type() bus.Type {
+ return CourseQueryType
+}
+
+// CourseQueryHandler is the bus handler
+// responsible for fetching courses.
+type CourseQueryHandler struct {
+ service FetchingCourseService
+}
+
+// NewCourseQueryHandler initializes a new NewCourseQueryHandler.
+func NewCourseQueryHandler(service FetchingCourseService) CourseQueryHandler {
+ return CourseQueryHandler{
+ service: service,
+ }
+}
+
+// Handle implements the bus.QueryHandler interface.
+func (h CourseQueryHandler) Handle(ctx context.Context, query bus.Query) (bus.QueryResponse, error) {
+ _, ok := query.(CourseQuery)
+ if !ok {
+ return nil, errors.New("unexpected bus")
+ }
+
+ return h.service.GetAll(ctx)
+}
diff --git a/04-03-command-bus/internal/fetching/service.go b/04-03-command-bus/internal/fetching/service.go
new file mode 100644
index 0000000..39ea302
--- /dev/null
+++ b/04-03-command-bus/internal/fetching/service.go
@@ -0,0 +1,25 @@
+package fetching
+
+import (
+ "context"
+
+ mooc "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal"
+)
+
+// CourseService is the default CourseService interface
+// implementation returned by fetching.NewCourseFetchingService.
+type FetchingCourseService struct {
+ courseRepository mooc.CourseRepository
+}
+
+// NewCourseService returns the default Service interface implementation.
+func NewCourseFetchingService(courseRepository mooc.CourseRepository) FetchingCourseService {
+ return FetchingCourseService{
+ courseRepository: courseRepository,
+ }
+}
+
+// CreateCourse implements the creating.CourseService interface.
+func (s FetchingCourseService) GetAll(ctx context.Context) ([]mooc.Course, error) {
+ return s.courseRepository.GetAll(ctx)
+}
diff --git a/04-03-command-bus/internal/platform/bus/inmemory/bus.go b/04-03-command-bus/internal/platform/bus/inmemory/bus.go
new file mode 100644
index 0000000..5ffa852
--- /dev/null
+++ b/04-03-command-bus/internal/platform/bus/inmemory/bus.go
@@ -0,0 +1,86 @@
+package inmemory
+
+import (
+ "context"
+ "log"
+
+ "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/bus"
+)
+
+// Bus is an in-memory implementation of the bus.Bus.
+type Bus struct {
+ commandsHandlers map[bus.Type]bus.CommandHandler
+ queryHandlers map[bus.Type]bus.QueryHandler
+ eventHandlers map[bus.Type]bus.EventHandler
+}
+
+// NewCommandBus initializes a new instance of Bus.
+func NewCommandBus() *Bus {
+ return &Bus{
+ commandsHandlers: make(map[bus.Type]bus.CommandHandler),
+ queryHandlers: make(map[bus.Type]bus.QueryHandler),
+ eventHandlers: make(map[bus.Type]bus.EventHandler),
+ }
+}
+
+// DispatchCommand implements the bus.Bus interface.
+func (b *Bus) DispatchCommand(ctx context.Context, cmd bus.Command) error {
+ handler, ok := b.commandsHandlers[cmd.Type()]
+ if !ok {
+ return nil
+ }
+
+ // Si dejo este asincronismo sucede que el endpoint del controller responde 201, cuando en verdad fallo. No tiene más sentido que el asincrnismo lo maneje el que lo llama?
+ /*go func() {
+ err := handler.Handle(ctx, cmd)
+ if err != nil {
+ log.Printf("Error while handling %s - %s\n", cmd.Type(), err)
+ }
+
+ }()*/
+
+ return handler.Handle(ctx, cmd)
+}
+
+// RegisterCommandHandler implements the bus.Bus interface.
+func (b *Bus) RegisterCommandHandler(cmdType bus.Type, handler bus.CommandHandler) {
+ b.commandsHandlers[cmdType] = handler
+}
+
+// DispatchQuery implements the bus.Bus interface.
+func (b *Bus) DispatchQuery(ctx context.Context, query bus.Query) (bus.QueryResponse, error) {
+ handler, ok := b.queryHandlers[query.Type()]
+ if !ok {
+ return nil, nil
+ }
+ // Como este es sincronico, decide el que lo usa si lo espera o no.
+ return handler.Handle(ctx, query)
+}
+
+// RegisterQueryHandler implements the bus.Bus interface.
+func (b *Bus) RegisterQueryHandler(queryType bus.Type, handler bus.QueryHandler) {
+ b.queryHandlers[queryType] = handler
+}
+
+// DispatchEvent implements the bus.Bus interface.
+func (b *Bus) DispatchEvent(ctx context.Context, event bus.Event) error {
+ handler, ok := b.eventHandlers[event.Type()]
+ if !ok {
+ return nil
+ }
+
+ go func() {
+ err := handler.Handle(ctx, event)
+ if err != nil {
+ log.Printf("Error while handling %s - %s\n", event.Type(), err)
+ }
+
+ }()
+
+ return nil
+}
+
+// RegisterEventHandler implements the bus.Bus interface.
+func (b *Bus) RegisterEventHandler(cmdType bus.Type, handler bus.EventHandler) {
+ b.eventHandlers[cmdType] = handler
+}
\ No newline at end of file
diff --git a/04-03-command-bus/internal/platform/bus/inmemory/command.go b/04-03-command-bus/internal/platform/bus/inmemory/command.go
deleted file mode 100644
index 08c4d19..0000000
--- a/04-03-command-bus/internal/platform/bus/inmemory/command.go
+++ /dev/null
@@ -1,43 +0,0 @@
-package inmemory
-
-import (
- "context"
- "log"
-
- "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/command"
-)
-
-// CommandBus is an in-memory implementation of the command.Bus.
-type CommandBus struct {
- handlers map[command.Type]command.Handler
-}
-
-// NewCommandBus initializes a new instance of CommandBus.
-func NewCommandBus() *CommandBus {
- return &CommandBus{
- handlers: make(map[command.Type]command.Handler),
- }
-}
-
-// Dispatch implements the command.Bus interface.
-func (b *CommandBus) Dispatch(ctx context.Context, cmd command.Command) error {
- handler, ok := b.handlers[cmd.Type()]
- if !ok {
- return nil
- }
-
- go func() {
- err := handler.Handle(ctx, cmd)
- if err != nil {
- log.Printf("Error while handling %s - %s\n", cmd.Type(), err)
- }
-
- }()
-
- return nil
-}
-
-// Register implements the command.Bus interface.
-func (b *CommandBus) Register(cmdType command.Type, handler command.Handler) {
- b.handlers[cmdType] = handler
-}
diff --git a/04-03-command-bus/internal/platform/server/handler/courses/create.go b/04-03-command-bus/internal/platform/server/handler/courses/create.go
index c178a7f..c62bcda 100644
--- a/04-03-command-bus/internal/platform/server/handler/courses/create.go
+++ b/04-03-command-bus/internal/platform/server/handler/courses/create.go
@@ -6,7 +6,7 @@ import (
mooc "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal"
"github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal/creating"
- "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/command"
+ "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/bus"
"github.com/gin-gonic/gin"
)
@@ -17,7 +17,7 @@ type createRequest struct {
}
// CreateHandler returns an HTTP handler for courses creation.
-func CreateHandler(commandBus command.Bus) gin.HandlerFunc {
+func CreateHandler(bus bus.Bus) gin.HandlerFunc {
return func(ctx *gin.Context) {
var req createRequest
if err := ctx.BindJSON(&req); err != nil {
@@ -25,7 +25,7 @@ func CreateHandler(commandBus command.Bus) gin.HandlerFunc {
return
}
- err := commandBus.Dispatch(ctx, creating.NewCourseCommand(
+ err := bus.DispatchCommand(ctx, creating.NewCourseCommand(
req.ID,
req.Name,
req.Duration,
diff --git a/04-03-command-bus/internal/platform/server/handler/courses/create_test.go b/04-03-command-bus/internal/platform/server/handler/courses/create_test.go
index 172c689..7bb5c4d 100644
--- a/04-03-command-bus/internal/platform/server/handler/courses/create_test.go
+++ b/04-03-command-bus/internal/platform/server/handler/courses/create_test.go
@@ -7,7 +7,7 @@ import (
"net/http/httptest"
"testing"
- "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/command/commandmocks"
+ "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/bus/busmocks"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
@@ -15,16 +15,16 @@ import (
)
func TestHandler_Create(t *testing.T) {
- commandBus := new(commandmocks.Bus)
- commandBus.On(
- "Dispatch",
+ bus := new(busmocks.Bus)
+ bus.On(
+ "DispatchCommand",
mock.Anything,
mock.AnythingOfType("creating.CourseCommand"),
).Return(nil)
gin.SetMode(gin.TestMode)
r := gin.New()
- r.POST("/courses", CreateHandler(commandBus))
+ r.POST("/courses", CreateHandler(bus))
t.Run("given an invalid request it returns 400", func(t *testing.T) {
createCourseReq := createRequest{
diff --git a/04-03-command-bus/internal/platform/server/handler/courses/get.go b/04-03-command-bus/internal/platform/server/handler/courses/get.go
new file mode 100644
index 0000000..07307c2
--- /dev/null
+++ b/04-03-command-bus/internal/platform/server/handler/courses/get.go
@@ -0,0 +1,41 @@
+package courses
+
+import (
+ mooc "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal"
+ "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal/fetching"
+ "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/bus"
+ "github.com/gin-gonic/gin"
+ "net/http"
+)
+
+type getResponse struct {
+ Id string `json:"id"`
+ Name string `json:"name"`
+ Duration string `json:"duration"`
+}
+
+// GetHandler returns an HTTP handler for courses.
+func GetHandler(queryBus bus.Bus) gin.HandlerFunc {
+ return func(ctx *gin.Context) {
+ var queryResponse, err = queryBus.DispatchQuery(ctx, fetching.NewFetchCourseQuery())
+
+ if err != nil {
+ // Si quiero devolver error en ves de la lista se rompe me genera un error de unmarshal
+ ctx.JSON(http.StatusInternalServerError, []getResponse{})
+ return
+ }
+ courses, ok := queryResponse.([]mooc.Course)
+ if ok {
+ var response = make([]getResponse, 0, len(courses))
+ for _, course := range courses {
+ response = append(response, getResponse{
+ Id: course.ID().String(),
+ Name: course.Name().String(),
+ Duration: course.Duration().String(),
+ })
+ }
+ ctx.JSON(http.StatusOK, response)
+ }
+ ctx.JSON(http.StatusInternalServerError, []getResponse{})
+ }
+}
diff --git a/04-03-command-bus/internal/platform/server/handler/courses/get_test.go b/04-03-command-bus/internal/platform/server/handler/courses/get_test.go
new file mode 100644
index 0000000..4884291
--- /dev/null
+++ b/04-03-command-bus/internal/platform/server/handler/courses/get_test.go
@@ -0,0 +1,85 @@
+package courses
+
+import (
+ "encoding/json"
+ "errors"
+ mooc "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal"
+ "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal/fetching"
+ "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal/platform/bus/inmemory"
+ "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal/platform/storage/storagemocks"
+ "github.com/gin-gonic/gin"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/mock"
+ "github.com/stretchr/testify/require"
+ "log"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+)
+
+func TestGetHandler(t *testing.T) {
+ tests := map[string]struct {
+ mockData []mooc.Course
+ mockError error
+ expectedResponse []getResponse
+ expectedStatus int
+ }{
+ "Empty repo return 200 with empty list": {
+ mockData: []mooc.Course{},
+ mockError: nil,
+ expectedStatus:http.StatusOK,
+ expectedResponse: []getResponse{}},
+ "Repo error return 500": {
+ mockData: []mooc.Course{},
+ mockError: errors.New("the field Duration can not be empty"),
+ expectedStatus:http.StatusInternalServerError,
+ expectedResponse: []getResponse{}},
+ "Fully repo return 200 with list of courses":{
+ mockData: []mooc.Course{ mockCourse("8a1c5cdc-ba57-445a-994d-aa412d23723f", "Courses Complete", "123")},
+ mockError: nil,
+ expectedStatus:http.StatusOK,
+ expectedResponse: []getResponse{{Id: "8a1c5cdc-ba57-445a-994d-aa412d23723f", Name: "Courses Complete", Duration: "123"}}},
+ }
+ for key, value := range tests {
+ t.Run(key, func(t *testing.T) {
+ courseRepository := storagemocks.CourseRepository{}
+ bus := inmemory.NewCommandBus()
+ fetchingCourseService := fetching.NewCourseFetchingService(&courseRepository)
+ fetchingCourseQueryHandler := fetching.NewCourseQueryHandler(fetchingCourseService)
+ bus.RegisterQueryHandler(fetching.CourseQueryType, fetchingCourseQueryHandler)
+
+ courseRepository.On(
+ "GetAll",
+ mock.Anything,
+ ).Return(value.mockData, value.mockError)
+ gin.SetMode(gin.TestMode)
+ r := gin.New()
+ r.GET("/courses", GetHandler(bus))
+
+ req, err := http.NewRequest(http.MethodGet, "/courses", nil)
+ require.NoError(t, err)
+
+ rec := httptest.NewRecorder()
+ r.ServeHTTP(rec, req)
+
+ res := rec.Result()
+ defer res.Body.Close()
+
+ assert.Equal(t, value.expectedStatus, res.StatusCode)
+ var response []getResponse
+ if err := json.NewDecoder(res.Body).Decode(&response); err != nil {
+ log.Fatalln(err)
+ }
+
+ assert.Equal(t, value.expectedResponse, response)
+ })
+ }
+}
+
+func mockCourse(id string, name string, duration string) mooc.Course {
+ course, err := mooc.NewCourse(id, name, duration)
+ if err != nil{
+ log.Fatalln(err)
+ }
+ return course
+}
diff --git a/04-03-command-bus/internal/platform/server/server.go b/04-03-command-bus/internal/platform/server/server.go
index 09c4d34..993ebb7 100644
--- a/04-03-command-bus/internal/platform/server/server.go
+++ b/04-03-command-bus/internal/platform/server/server.go
@@ -6,7 +6,7 @@ import (
"github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal/platform/server/handler/courses"
"github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/internal/platform/server/handler/health"
- "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/command"
+ "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/bus"
"github.com/gin-gonic/gin"
)
@@ -15,15 +15,15 @@ type Server struct {
engine *gin.Engine
// deps
- commandBus command.Bus
+ bus bus.Bus
}
-func New(host string, port uint, commandBus command.Bus) Server {
+func New(host string, port uint, bus bus.Bus) Server {
srv := Server{
engine: gin.New(),
httpAddr: fmt.Sprintf("%s:%d", host, port),
- commandBus: commandBus,
+ bus: bus,
}
srv.registerRoutes()
@@ -37,5 +37,6 @@ func (s *Server) Run() error {
func (s *Server) registerRoutes() {
s.engine.GET("/health", health.CheckHandler())
- s.engine.POST("/courses", courses.CreateHandler(s.commandBus))
+ s.engine.POST("/courses", courses.CreateHandler(s.bus))
+ s.engine.GET("/courses", courses.GetHandler(s.bus))
}
diff --git a/04-03-command-bus/internal/platform/storage/mysql/course_repository.go b/04-03-command-bus/internal/platform/storage/mysql/course_repository.go
index be308b4..08186ce 100644
--- a/04-03-command-bus/internal/platform/storage/mysql/course_repository.go
+++ b/04-03-command-bus/internal/platform/storage/mysql/course_repository.go
@@ -37,3 +37,34 @@ func (r *CourseRepository) Save(ctx context.Context, course mooc.Course) error {
return nil
}
+
+
+// GetAll implements the mooc.CourseRepository interface.
+func (r *CourseRepository) GetAll(ctx context.Context) (courses []mooc.Course, err error) {
+ courseSQLStruct := sqlbuilder.NewSelectBuilder()
+ courseSQLStruct.Select("id", "name", "duration")
+ courseSQLStruct.From(sqlCourseTable)
+
+ sqlQuery, args := courseSQLStruct.Build()
+
+
+ rows, err := r.db.QueryContext(ctx, sqlQuery, args...)
+ if err != nil {
+ return nil, fmt.Errorf("error trying to get course on database: %v", err)
+ }
+ defer rows.Close()
+ courses = []mooc.Course{}
+ for rows.Next() {
+ var sqlCourse sqlCourse
+ err := rows.Scan(sqlCourse.ID, sqlCourse.Name, sqlCourse.Duration)
+ if err != nil {
+ return nil, err
+ }
+ course, err := mooc.NewCourse(sqlCourse.ID, sqlCourse.Name, sqlCourse.Duration)
+ if err != nil {
+ return nil, err
+ }
+ courses = append(courses, course)
+ }
+ return courses, nil
+}
\ No newline at end of file
diff --git a/04-03-command-bus/internal/platform/storage/storagemocks/course_repository.go b/04-03-command-bus/internal/platform/storage/storagemocks/course_repository.go
index 146a323..6b364cd 100644
--- a/04-03-command-bus/internal/platform/storage/storagemocks/course_repository.go
+++ b/04-03-command-bus/internal/platform/storage/storagemocks/course_repository.go
@@ -14,6 +14,29 @@ type CourseRepository struct {
mock.Mock
}
+// GetAll provides a mock function with given fields: ctx
+func (_m *CourseRepository) GetAll(ctx context.Context) ([]mooc.Course, error) {
+ ret := _m.Called(ctx)
+
+ var r0 []mooc.Course
+ if rf, ok := ret.Get(0).(func(context.Context) []mooc.Course); ok {
+ r0 = rf(ctx)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).([]mooc.Course)
+ }
+ }
+
+ var r1 error
+ if rf, ok := ret.Get(1).(func(context.Context) error); ok {
+ r1 = rf(ctx)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
// Save provides a mock function with given fields: ctx, course
func (_m *CourseRepository) Save(ctx context.Context, course mooc.Course) error {
ret := _m.Called(ctx, course)
diff --git a/04-03-command-bus/kit/bus/bus.go b/04-03-command-bus/kit/bus/bus.go
new file mode 100644
index 0000000..f978c79
--- /dev/null
+++ b/04-03-command-bus/kit/bus/bus.go
@@ -0,0 +1,57 @@
+package bus
+
+import "context"
+
+// Bus defines the expected behaviour from a bus bus.
+type Bus interface {
+ // DispatchCommand is the method used to dispatch new commands.
+ DispatchCommand(context.Context, Command) error
+ // RegisterCommandHandler is the method used to register a new command handler.
+ RegisterCommandHandler(Type, CommandHandler)
+ // DispatchQuery is the method used to dispatch new queries.
+ DispatchQuery(context.Context, Query) (QueryResponse, error)
+ // RegisterQueryHandler is the method used to register a new query handler.
+ RegisterQueryHandler(Type, QueryHandler)
+ // DispatchEvent is the method used to dispatch new event.
+ DispatchEvent(context.Context, Event) error
+ // RegisterEventHandler is the method used to register a new event handler.
+ RegisterEventHandler(Type, EventHandler)
+}
+
+//go:generate mockery --case=snake --outpkg=busmocks --output=busmocks --name=Bus
+
+// Type represents an application bus type.
+type Type string
+
+// Command represents an application bus.
+type Command interface {
+ Type() Type
+}
+
+// CommandHandler defines the expected behaviour from a bus handler.
+type CommandHandler interface {
+ Handle(context.Context, Command) error
+}
+
+// Query represents an application bus.
+type Query interface {
+ Type() Type
+}
+
+type QueryResponse interface{}
+
+// QueryHandler defines the expected behaviour from a bus handler.
+type QueryHandler interface {
+ Handle(context.Context, Query) (QueryResponse, error)
+}
+
+
+// Event represents an application bus.
+type Event interface {
+ Type() Type
+}
+
+// EventHandler defines the expected behaviour from a bus handler.
+type EventHandler interface {
+ Handle(context.Context, Event) error
+}
diff --git a/04-03-command-bus/kit/bus/busmocks/bus.go b/04-03-command-bus/kit/bus/busmocks/bus.go
new file mode 100644
index 0000000..fbdd0c5
--- /dev/null
+++ b/04-03-command-bus/kit/bus/busmocks/bus.go
@@ -0,0 +1,82 @@
+// Code generated by mockery v0.0.0-dev. DO NOT EDIT.
+
+package busmocks
+
+import (
+ context "context"
+
+ bus "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/bus"
+
+ mock "github.com/stretchr/testify/mock"
+)
+
+// Bus is an autogenerated mock type for the Bus type
+type Bus struct {
+ mock.Mock
+}
+
+// DispatchCommand provides a mock function with given fields: _a0, _a1
+func (_m *Bus) DispatchCommand(_a0 context.Context, _a1 bus.Command) error {
+ ret := _m.Called(_a0, _a1)
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, bus.Command) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// DispatchEvent provides a mock function with given fields: _a0, _a1
+func (_m *Bus) DispatchEvent(_a0 context.Context, _a1 bus.Event) error {
+ ret := _m.Called(_a0, _a1)
+
+ var r0 error
+ if rf, ok := ret.Get(0).(func(context.Context, bus.Event) error); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ r0 = ret.Error(0)
+ }
+
+ return r0
+}
+
+// DispatchQuery provides a mock function with given fields: _a0, _a1
+func (_m *Bus) DispatchQuery(_a0 context.Context, _a1 bus.Query) (bus.QueryResponse, error) {
+ ret := _m.Called(_a0, _a1)
+
+ var r0 bus.QueryResponse
+ if rf, ok := ret.Get(0).(func(context.Context, bus.Query) bus.QueryResponse); ok {
+ r0 = rf(_a0, _a1)
+ } else {
+ if ret.Get(0) != nil {
+ r0 = ret.Get(0).(bus.QueryResponse)
+ }
+ }
+
+ var r1 error
+ if rf, ok := ret.Get(1).(func(context.Context, bus.Query) error); ok {
+ r1 = rf(_a0, _a1)
+ } else {
+ r1 = ret.Error(1)
+ }
+
+ return r0, r1
+}
+
+// RegisterCommandHandler provides a mock function with given fields: _a0, _a1
+func (_m *Bus) RegisterCommandHandler(_a0 bus.Type, _a1 bus.CommandHandler) {
+ _m.Called(_a0, _a1)
+}
+
+// RegisterEventHandler provides a mock function with given fields: _a0, _a1
+func (_m *Bus) RegisterEventHandler(_a0 bus.Type, _a1 bus.EventHandler) {
+ _m.Called(_a0, _a1)
+}
+
+// RegisterQueryHandler provides a mock function with given fields: _a0, _a1
+func (_m *Bus) RegisterQueryHandler(_a0 bus.Type, _a1 bus.QueryHandler) {
+ _m.Called(_a0, _a1)
+}
diff --git a/04-03-command-bus/kit/command/command.go b/04-03-command-bus/kit/command/command.go
deleted file mode 100644
index a7f36bc..0000000
--- a/04-03-command-bus/kit/command/command.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package command
-
-import "context"
-
-// Bus defines the expected behaviour from a command bus.
-type Bus interface {
- // Dispatch is the method used to dispatch new commands.
- Dispatch(context.Context, Command) error
- // Register is the method used to register a new command handler.
- Register(Type, Handler)
-}
-
-//go:generate mockery --case=snake --outpkg=commandmocks --output=commandmocks --name=Bus
-
-// Type represents an application command type.
-type Type string
-
-// Command represents an application command.
-type Command interface {
- Type() Type
-}
-
-// Handler defines the expected behaviour from a command handler.
-type Handler interface {
- Handle(context.Context, Command) error
-}
diff --git a/04-03-command-bus/kit/command/commandmocks/bus.go b/04-03-command-bus/kit/command/commandmocks/bus.go
deleted file mode 100644
index 347ea4e..0000000
--- a/04-03-command-bus/kit/command/commandmocks/bus.go
+++ /dev/null
@@ -1,35 +0,0 @@
-// Code generated by mockery v0.0.0-dev. DO NOT EDIT.
-
-package commandmocks
-
-import (
- context "context"
-
- command "github.com/CodelyTV/go-hexagonal_http_api-course/04-03-command-bus/kit/command"
-
- mock "github.com/stretchr/testify/mock"
-)
-
-// Bus is an autogenerated mock type for the Bus type
-type Bus struct {
- mock.Mock
-}
-
-// Dispatch provides a mock function with given fields: _a0, _a1
-func (_m *Bus) Dispatch(_a0 context.Context, _a1 command.Command) error {
- ret := _m.Called(_a0, _a1)
-
- var r0 error
- if rf, ok := ret.Get(0).(func(context.Context, command.Command) error); ok {
- r0 = rf(_a0, _a1)
- } else {
- r0 = ret.Error(0)
- }
-
- return r0
-}
-
-// Register provides a mock function with given fields: _a0, _a1
-func (_m *Bus) Register(_a0 command.Type, _a1 command.Handler) {
- _m.Called(_a0, _a1)
-}