-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
15 changed files
with
371 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes
File renamed without changes
File renamed without changes
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package handler | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/gofiber/fiber/v2" | ||
"github.com/gofiber/fiber/v2/log" | ||
"github.com/sebajax/go-vertical-slice-architecture/internal/user" | ||
"github.com/sebajax/go-vertical-slice-architecture/internal/user/service" | ||
"github.com/sebajax/go-vertical-slice-architecture/pkg/apperror" | ||
"github.com/sebajax/go-vertical-slice-architecture/pkg/message" | ||
"github.com/sebajax/go-vertical-slice-architecture/pkg/validate" | ||
) | ||
|
||
// Body request schema for CreateUser | ||
type UserSchema struct { | ||
IdentityNumber string `json:"identity_number" validate:"required,min=6"` | ||
FirstName string `json:"first_name" validate:"required,min=2"` | ||
LastName string `json:"last_name" validate:"required,min=2"` | ||
Email string `json:"email" validate:"required,email"` | ||
DateOfBirth time.Time `json:"date_of_birth" validate:"required"` | ||
} | ||
|
||
// Creates a new user into the database | ||
func CreateUser(s service.CreateUserService) fiber.Handler { | ||
return func(c *fiber.Ctx) error { | ||
// Get body request | ||
var body UserSchema | ||
// Validate the body | ||
err := c.BodyParser(&body) | ||
if err != nil { | ||
// Map the error and response via the middleware | ||
log.Error(err) | ||
return err | ||
} | ||
|
||
// Validate schema | ||
serr, err := validate.Validate(body) | ||
if err != nil { | ||
log.Error(serr) | ||
return apperror.BadRequest(serr) | ||
} | ||
|
||
// No schema errores then map body to domain | ||
user := &user.User{ | ||
IdentityNumber: body.IdentityNumber, | ||
FirstName: body.FirstName, | ||
LastName: body.LastName, | ||
Email: body.Email, | ||
DateOfBirth: body.DateOfBirth, | ||
} | ||
|
||
// Execute the service | ||
result, err := s.CreateUser(user) | ||
if err != nil { | ||
// if service response an error return via the middleware | ||
log.Error(err) | ||
return err | ||
} | ||
|
||
// Success execution | ||
return c.Status(fiber.StatusCreated).JSON(message.SuccessResponse(&result)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package handler | ||
|
||
import ( | ||
"github.com/gofiber/fiber/v2" | ||
"github.com/sebajax/go-vertical-slice-architecture/internal/user/service" | ||
) | ||
|
||
// UserRouter is the Router for GoFiber App | ||
func UserRouter(app fiber.Router, s *service.UserService) { | ||
app.Post("/", CreateUser(s.CreateUserServiceProvider)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package infrastructure | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
|
||
"github.com/sebajax/go-vertical-slice-architecture/internal/user" | ||
"github.com/sebajax/go-vertical-slice-architecture/pkg/database" | ||
) | ||
|
||
// User repository for querying the database | ||
type userRepository struct { | ||
db *database.DbConn | ||
} | ||
|
||
// Create a user instance repository | ||
func NewUserRepository(dbcon *database.DbConn) user.UserRepository { | ||
return &userRepository{db: dbcon} | ||
} | ||
|
||
// Stores a new user in the database | ||
func (repo *userRepository) Save(u *user.User) (int64, error) { | ||
// Get the id inserted in the database | ||
var id int64 | ||
|
||
query := `INSERT INTO client (identity_number, first_name, last_name, email, date_of_birth) | ||
VALUES ($1, $2, $3, $4, $5) RETURNING id` | ||
err := repo.db.DbPool.QueryRow(query, u.IdentityNumber, u.FirstName, u.LastName, u.Email, u.DateOfBirth).Scan(&id) | ||
if err != nil { | ||
return 0, err | ||
} | ||
|
||
fmt.Println("id: ", id) | ||
|
||
// No errors return the user id inserted | ||
return id, nil | ||
} | ||
|
||
// Gets the user by the email | ||
func (repo *userRepository) GetByEmail(email string) (*user.User, bool, error) { | ||
u := user.User{} | ||
query := `SELECT id, identity_number, first_name, last_name, email, date_of_birth, created_at | ||
FROM client | ||
WHERE email = $1` | ||
err := repo.db.DbPool.QueryRow(query, email).Scan(&u.Id, &u.IdentityNumber, &u.FirstName, &u.LastName, &u.Email, &u.DateOfBirth, &u.CreatedAt) | ||
if err != nil { | ||
// Not found, but not an error | ||
if err == sql.ErrNoRows { | ||
return nil, false, nil | ||
} | ||
// An actual error occurred | ||
return nil, false, err | ||
} | ||
|
||
// Found the item | ||
return &u, true, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package mocks | ||
|
||
import "github.com/sebajax/go-vertical-slice-architecture/internal/user" | ||
|
||
type mockUserRepository struct{} | ||
|
||
func NewMockUserRepository() user.UserRepository { | ||
return &mockUserRepository{} | ||
} | ||
|
||
func (mock *mockUserRepository) Save(u *user.User) (int64, error) { | ||
return 1, nil | ||
} | ||
|
||
func (mock *mockUserRepository) GetByEmail(email string) (*user.User, bool, error) { | ||
/*return &user.User{ | ||
Id: 1, | ||
Email: "[email protected]", | ||
Name: "Juan", | ||
DateOfBirth: time.Now(), | ||
CreatedAt: time.Now(), | ||
}, true, nil*/ | ||
return nil, true, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package user | ||
|
||
// User port interface definition for depedency injection | ||
type UserRepository interface { | ||
Save(u *User) (int64, error) | ||
GetByEmail(email string) (*User, bool, error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package product | ||
|
||
import "time" | ||
|
||
// ProductCategory represents the categories of electronic products | ||
type ProductCategory int | ||
|
||
// Enumeration of product categories | ||
const ( | ||
Laptop ProductCategory = iota | ||
Smartphone | ||
Tablet | ||
SmartWatch | ||
Headphones | ||
Camera | ||
Television | ||
Other | ||
) | ||
|
||
// String representation of the ProductCategory | ||
func (p ProductCategory) String() string { | ||
return [...]string{ | ||
"Laptop", | ||
"Smartphone", | ||
"Tablet", | ||
"SmartWatch", | ||
"Headphones", | ||
"Camera", | ||
"Television", | ||
"Other", | ||
} | ||
} | ||
|
||
// Const for error messages | ||
const ( | ||
ErrorSkuExists string = "ERROR_SKU_EXISTS" | ||
ErrorWrongCategory string = "ERROR_WRONG_CATEGORY" | ||
) | ||
|
||
// Product Domain | ||
type User struct { | ||
Id int | ||
Name string | ||
Sku string | ||
Category ProductCategory | ||
Price string | ||
CreatedAt time.Time | ||
} | ||
|
||
// Create a new product instance | ||
func New(n string, s string, c string, p string) (*Product, error) { | ||
return &Product{ | ||
Name: n, | ||
Sku: s, | ||
Category: c, | ||
Price: p, | ||
}, nil | ||
} |
Oops, something went wrong.