Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
hirotakan committed Dec 10, 2016
0 parents commit 09d8567
Show file tree
Hide file tree
Showing 16 changed files with 383 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
vendor/
27 changes: 27 additions & 0 deletions docker-compose.yml
@@ -0,0 +1,27 @@
version: '2'
services:
db:
image: mysql:5.7
environment:
MYSQL_DATABASE: sample
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
volumes:
- db-data:/var/lib/mysql
- ./mysql:/docker-entrypoint-initdb.d
ports:
- "3306:3306"
app:
image: golang:1.6
environment:
MYAPP_DATABASE_HOST: db
command: "go run server.go"
volumes:
- ./src:/go/src
working_dir: /go/src/app
ports:
- "8080:8080"
links:
- db

volumes:
db-data:
12 changes: 12 additions & 0 deletions mysql/setup.sql
@@ -0,0 +1,12 @@
CREATE TABLE users (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
first_name VARCHAR(20) NOT NULL,
last_name VARCHAR(20) NOT NULL,
PRIMARY KEY (id)
);

insert into users(first_name, last_name) values("Patricia", "Smith");
insert into users(first_name, last_name) values("Linda", "Johnson");
insert into users(first_name, last_name) values("Mary", "William");
insert into users(first_name, last_name) values("Robert", "Jones");
insert into users(first_name, last_name) values("James", "Brown");
17 changes: 17 additions & 0 deletions src/app/domain/user.go
@@ -0,0 +1,17 @@
package domain

import "fmt"

type Users []User

type User struct {
ID int
FirstName string
LastName string
FullName string
}

func (u *User) Build() *User {
u.FullName = fmt.Sprintf("%s %s", u.FirstName, u.LastName)
return u
}
33 changes: 33 additions & 0 deletions src/app/glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/app/glide.yaml
@@ -0,0 +1,6 @@
package: .
import:
- package: github.com/go-sql-driver/mysql
version: v1.3
- package: gopkg.in/gin-gonic/gin.v1
version: v1.1.4
21 changes: 21 additions & 0 deletions src/app/infrastructure/router.go
@@ -0,0 +1,21 @@
package infrastructure

import (
gin "gopkg.in/gin-gonic/gin.v1"

"app/interfaces/controllers"
)

var Router *gin.Engine

func init() {
router := gin.Default()

userController := controllers.NewUserController(NewSqlHandler())

router.POST("/users", func(c *gin.Context) { userController.Create(c) })
router.GET("/users", func(c *gin.Context) { userController.Index(c) })
router.GET("/users/:id", func(c *gin.Context) { userController.Show(c) })

Router = router
}
71 changes: 71 additions & 0 deletions src/app/infrastructure/sqlhandler.go
@@ -0,0 +1,71 @@
package infrastructure

import (
"database/sql"

_ "github.com/go-sql-driver/mysql"

"app/interfaces/database"
)

type SqlHandler struct {
Conn *sql.DB
}

func NewSqlHandler() database.SqlHandler {
conn, err := sql.Open("mysql", "root:@tcp(db:3306)/sample")
if err != nil {
panic(err.Error)
}
sqlHandler := new(SqlHandler)
sqlHandler.Conn = conn
return sqlHandler
}

func (handler *SqlHandler) Execute(statement string, args ...interface{}) (database.Result, error) {
res := SqlResult{}
result, err := handler.Conn.Exec(statement, args...)
if err != nil {
return res, err
}
res.Result = result
return res, nil
}

func (handler *SqlHandler) Query(statement string, args ...interface{}) (database.Row, error) {
rows, err := handler.Conn.Query(statement, args...)
if err != nil {
return new(SqlRow), err
}
row := new(SqlRow)
row.Rows = rows
return row, nil
}

type SqlResult struct {
Result sql.Result
}

func (r SqlResult) LastInsertId() (int64, error) {
return r.Result.LastInsertId()
}

func (r SqlResult) RowsAffected() (int64, error) {
return r.Result.RowsAffected()
}

type SqlRow struct {
Rows *sql.Rows
}

func (r SqlRow) Scan(dest ...interface{}) error {
return r.Rows.Scan(dest...)
}

func (r SqlRow) Next() bool {
return r.Rows.Next()
}

func (r SqlRow) Close() error {
return r.Rows.Close()
}
8 changes: 8 additions & 0 deletions src/app/interfaces/controllers/context.go
@@ -0,0 +1,8 @@
package controllers

type Context interface {
Param(string) string
Bind(interface{}) error
Status(int)
JSON(int, interface{})
}
11 changes: 11 additions & 0 deletions src/app/interfaces/controllers/error.go
@@ -0,0 +1,11 @@
package controllers

type Error struct {
Message string
}

func NewError(err error) *Error {
return &Error{
Message: err.Error(),
}
}
52 changes: 52 additions & 0 deletions src/app/interfaces/controllers/user_controller.go
@@ -0,0 +1,52 @@
package controllers

import (
"app/domain"
"app/interfaces/database"
"app/usecase"
"strconv"
)

type UserController struct {
Interactor usecase.UserInteractor
}

func NewUserController(sqlHandler database.SqlHandler) *UserController {
return &UserController{
Interactor: usecase.UserInteractor{
UserRepository: &database.UserRepository{
SqlHandler: sqlHandler,
},
},
}
}

func (controller *UserController) Create(c Context) {
u := domain.User{}
c.Bind(&u)
user, err := controller.Interactor.Add(u)
if err != nil {
c.JSON(500, NewError(err))
return
}
c.JSON(201, user)
}

func (controller *UserController) Index(c Context) {
users, err := controller.Interactor.Users()
if err != nil {
c.JSON(500, NewError(err))
return
}
c.JSON(200, users)
}

func (controller *UserController) Show(c Context) {
id, _ := strconv.Atoi(c.Param("id"))
user, err := controller.Interactor.UserById(id)
if err != nil {
c.JSON(500, NewError(err))
return
}
c.JSON(200, user)
}
17 changes: 17 additions & 0 deletions src/app/interfaces/database/sqlhandler.go
@@ -0,0 +1,17 @@
package database

type SqlHandler interface {
Execute(string, ...interface{}) (Result, error)
Query(string, ...interface{}) (Row, error)
}

type Result interface {
LastInsertId() (int64, error)
RowsAffected() (int64, error)
}

type Row interface {
Scan(...interface{}) error
Next() bool
Close() error
}
65 changes: 65 additions & 0 deletions src/app/interfaces/database/user_repository.go
@@ -0,0 +1,65 @@
package database

import "app/domain"

type UserRepository struct {
SqlHandler
}

func (repo *UserRepository) Store(u domain.User) (id int, err error) {
result, err := repo.Execute(
"INSERT INTO users (first_name, last_name) VALUES (?,?)", u.FirstName, u.LastName,
)
if err != nil {
return
}
id64, err := result.LastInsertId()
if err != nil {
return
}
id = int(id64)
return
}

func (repo *UserRepository) FindById(identifier int) (user domain.User, err error) {
row, err := repo.Query("SELECT id, first_name, last_name FROM users WHERE id = ?", identifier)
defer row.Close()
if err != nil {
return
}
var id int
var firstName string
var lastName string
row.Next()
if err = row.Scan(&id, &firstName, &lastName); err != nil {
return
}
user.ID = id
user.FirstName = firstName
user.LastName = lastName
user.Build()
return
}

func (repo *UserRepository) FindAll() (users domain.Users, err error) {
rows, err := repo.Query("SELECT id, first_name, last_name FROM users")
defer rows.Close()
if err != nil {
return
}
for rows.Next() {
var id int
var firstName string
var lastName string
if err := rows.Scan(&id, &firstName, &lastName); err != nil {
continue
}
user := domain.User{
ID: id,
FirstName: firstName,
LastName: lastName,
}
users = append(users, *user.Build())
}
return
}
7 changes: 7 additions & 0 deletions src/app/server.go
@@ -0,0 +1,7 @@
package main

import "app/infrastructure"

func main() {
infrastructure.Router.Run()
}
26 changes: 26 additions & 0 deletions src/app/usecase/user_interactor.go
@@ -0,0 +1,26 @@
package usecase

import "app/domain"

type UserInteractor struct {
UserRepository UserRepository
}

func (interactor *UserInteractor) Add(u domain.User) (user domain.User, err error) {
identifier, err := interactor.UserRepository.Store(u)
if err != nil {
return
}
user, err = interactor.UserRepository.FindById(identifier)
return
}

func (interactor *UserInteractor) Users() (user domain.Users, err error) {
user, err = interactor.UserRepository.FindAll()
return
}

func (interactor *UserInteractor) UserById(identifier int) (user domain.User, err error) {
user, err = interactor.UserRepository.FindById(identifier)
return
}
9 changes: 9 additions & 0 deletions src/app/usecase/user_repository.go
@@ -0,0 +1,9 @@
package usecase

import "app/domain"

type UserRepository interface {
Store(domain.User) (int, error)
FindById(int) (domain.User, error)
FindAll() (domain.Users, error)
}

0 comments on commit 09d8567

Please sign in to comment.