Last active
April 17, 2017 18:27
-
-
Save brunoksato/0d6b95d4eb293f15fa5ffc416c8a5e0e to your computer and use it in GitHub Desktop.
Generics.go
This file contains hidden or 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
// | |
//models | |
// | |
type Model struct { | |
ID uint `json:"id" gorm:"primary_key"` | |
CreatedAt time.Time `json:"-" sql:"DEFAULT:current_timestamp"` | |
UpdatedAt time.Time `json:"-" sql:"DEFAULT:current_timestamp"` | |
DeletedAt *time.Time `json:"-" settable:"false"` | |
} | |
type User struct { | |
Model | |
Name string `json:"name,omitempty" sql:"not null" valid:"length(3|50)"` | |
Password string `json:"password,omitempty"` | |
HashedPassword []byte `json:"-" sql:"hashed_password;not null"` | |
Birthday *time.Time `json:"birthday,omitempty"` | |
Image string `json:"img,omitempty"` | |
Gender uint `json:"gender"` | |
Phone string `json:"phone"` | |
Status uint `json:"status"` | |
} | |
type Category struct { | |
Model | |
Name string `json:"name,omitempty" sql:"not null"` | |
Description string `json:"description,omitempty"` | |
Image string `json:"image,omitempty"` | |
ImageMobileBackground string `json:"imb,omitempty"` | |
ImageBackground string `json:"ib,omitempty"` | |
Order uint `json:"order,omitempty"` | |
Status uint `json:"status"` | |
SubCategory []SubCategory `json:"sc,omitempty" fetch:"eager"` //this fetch use in BasicJoins automatic Preload | |
} | |
type SubCategory struct { | |
Model | |
Name string `json:"name,omitempty" sql:"not null"` | |
Description string `json:"description,omitempty"` | |
Image string `json:"image,omitempty"` | |
Status uint `json:"status"` | |
Category *Category `json:"c,omitempty"` | |
CategoryID uint `json:"cid" sql:"index"` | |
} | |
// | |
//handlers | |
// | |
func (ctx *Context) List(c echo.Context) error { | |
db := ctx.Database | |
db = BasicJoins(ctx, c, db) | |
db = BasicPaging(ctx, c, db, true) | |
items := reflect.New(reflect.SliceOf(ctx.Type)).Interface() | |
err := db.Find(items).Error | |
if err != nil { | |
return c.JSON(http.StatusBadRequest, NewServerError(err.Error())) | |
} | |
items = itemsOrEmptySlice(ctx.Type, items) | |
if ctx.Payload["ct"] != nil { | |
ctx.Payload["results"] = items | |
return c.JSON(http.StatusOK, ctx.Payload) | |
} | |
return c.JSON(http.StatusOK, items) | |
} | |
func (ctx *Context) Create(c echo.Context) error { | |
item := reflect.New(ctx.Type).Interface() | |
if err := c.Bind(item); err != nil { | |
return c.JSON(http.StatusBadRequest, NewServerError(err.Error())) | |
} | |
valerr := BasicValidationForCreate(ctx, c, item) | |
if valerr != nil { | |
return c.JSON(http.StatusBadRequest, NewServerError(valerr.Error())) | |
} | |
dberr := ctx.Database.Create(item).Error | |
if dberr != nil { | |
return c.JSON(http.StatusBadRequest, NewServerError(dberr.Error())) | |
} | |
return c.JSON(http.StatusCreated, item) | |
} | |
func (ctx *Context) Get(c echo.Context) error { | |
id, err := strconv.Atoi(c.Param("id")) | |
if err != nil { | |
return c.JSON(http.StatusNotFound, NewServerError(err.Error())) | |
} | |
item := reflect.New(ctx.Type).Interface() | |
db := ctx.Database | |
db = BasicJoins(ctx, c, db) | |
err = db.First(item, id).Error | |
if err != nil { | |
return c.JSON(http.StatusBadRequest, NewServerError(err.Error())) | |
} | |
return c.JSON(http.StatusOK, item) | |
} | |
func (ctx *Context) Update(c echo.Context) error { | |
id, err := strconv.Atoi(c.Param("id")) | |
if err != nil { | |
return c.JSON(http.StatusNotFound, NewServerError(err.Error())) | |
} | |
item := reflect.New(ctx.Type).Interface() | |
err = ctx.Database.First(item, id).Error | |
if err != nil { | |
return c.JSON(http.StatusBadRequest, NewServerError(err.Error())) | |
} | |
err = BasicValidationForUpdate(ctx, c, item) | |
if err != nil { | |
return c.JSON(http.StatusBadRequest, NewServerError(err.Error())) | |
} | |
if err := c.Bind(item); err != nil { | |
return c.JSON(http.StatusBadRequest, NewServerError(err.Error())) | |
} | |
ctx.Database.Set("gorm:save_associations", false).Save(item) | |
if ctx.Database.Error != nil { | |
return c.JSON(http.StatusBadRequest, NewServerError(ctx.Database.Error.Error())) | |
} | |
return c.JSON(http.StatusAccepted, item) | |
} | |
func (ctx *Context) Delete(c echo.Context) error { | |
id, err := strconv.Atoi(c.Param("id")) | |
if err != nil { | |
return c.JSON(http.StatusNotFound, NewServerError(err.Error())) | |
} | |
item := reflect.New(ctx.Type).Interface() | |
err = ctx.Database.First(item, id).Error | |
if err != nil { | |
return c.JSON(http.StatusBadRequest, NewServerError(err.Error())) | |
} | |
err = ctx.Database.Delete(item).Error | |
if err != nil { | |
return c.JSON(http.StatusBadRequest, NewServerError(err.Error())) | |
} | |
return c.JSON(http.StatusOK, item) | |
} | |
func BasicJoins(ctx *Context, c echo.Context, db *gorm.DB) *gorm.DB { | |
db = joinsFor(db, ctx) | |
return db | |
} | |
func joinsFor(db *gorm.DB, ctx *Context) *gorm.DB { | |
t := ctx.Type | |
elemT := t | |
if elemT.Kind() == reflect.Ptr { | |
elemT = elemT.Elem() | |
} | |
for i := 0; i < elemT.NumField(); i++ { | |
f := elemT.Field(i) | |
tag := elemT.Field(i).Tag | |
fetch := tag.Get("fetch") | |
if fetch == "eager" { | |
db = db.Preload(f.Name) | |
} | |
} | |
return db | |
} | |
func BasicPaging(ctx *Context, c echo.Context, db *gorm.DB, count bool) *gorm.DB { | |
st := c.QueryParam("start") | |
limit := c.QueryParam("limit") | |
if st != "" { | |
startIdx, _ := strconv.Atoi(st) | |
if startIdx > 0 { | |
db = db.Offset(startIdx) | |
} | |
} | |
if limit != "" { | |
limitIdx, _ := strconv.Atoi(limit) | |
if limitIdx > 0 { | |
db = db.Limit(limitIdx) | |
if count { | |
QueryTotalCount(ctx) | |
} | |
} | |
} | |
return db | |
} | |
func QueryTotalCount(ctx *Context) { | |
item := reflect.New(ctx.Type).Interface() | |
var n int | |
ctx.Database.Model(item). | |
Select("COUNT(*)"). | |
Row(). | |
Scan(&n) | |
ctx.Payload["ct"] = n | |
} | |
func itemsOrEmptySlice(t reflect.Type, items interface{}) interface{} { | |
if reflect.ValueOf(items).IsNil() { | |
items = reflect.MakeSlice(reflect.SliceOf(t), 0, 0) | |
} | |
return items | |
} | |
func BasicValidationForCreate(ctx *Context, c echo.Context, item interface{}) mondo.MondoError { | |
if model.IsValidator(ctx.Type) { | |
validator := item.(mondo.Validator) | |
return validator.ValidateForCreate() | |
} else { | |
return nil | |
} | |
} | |
func BasicValidationForUpdate(ctx *Context, c echo.Context, item interface{}) error { | |
if model.IsValidator(ctx.Type) { | |
return mondo.ValidateStructFields(item) | |
} else { | |
return nil | |
} | |
} | |
// | |
//middleware | |
// | |
type Context struct { | |
Database *gorm.DB | |
Payload map[string]interface{} | |
Type reflect.Type | |
ParentType reflect.Type | |
} | |
func PathParts(path string) []string { | |
parts := strings.Split(strings.Trim(path, " /"), "/") | |
return parts | |
} | |
func (ctx *Context) DetermineType(next echo.HandlerFunc) echo.HandlerFunc { | |
return func(c echo.Context) error { | |
parts := PathParts(c.Path()) | |
var pathType string | |
for i := 0; i < len(parts); i++ { | |
pathType = parts[i] | |
t, name := StringToType(pathType) | |
if t != nil { | |
if ctx.Type != nil { | |
ctx.ParentType = ctx.Type | |
} | |
ctx.Type = t | |
} | |
} | |
return next(c) | |
} | |
} | |
func StringToType(typeName string) (t reflect.Type, name string) { | |
switch typeName { | |
case "users": | |
var m mondo.User | |
t = reflect.TypeOf(m) | |
case "categories": | |
var m mondo.Category | |
t = reflect.TypeOf(m) | |
case "sub_categories": | |
var m mondo.SubCategory | |
t = reflect.TypeOf(m) | |
return | |
} | |
// | |
//routers | |
// | |
private.GET("/users", ctx.List) | |
private.GET("/users/:id", ctx.Get) | |
private.POST("/users", ctx.Create) | |
private.PUT("/users/:id", ctx.Update) | |
private.DELETE("/users/:id", ctx.Delete) | |
private.GET("/categories", ctx.List) | |
private.GET("/categories/:id", ctx.Get) | |
private.POST("/categories", ctx.Create) | |
private.PUT("/categories/:id", ctx.Update) | |
private.DELETE("/categories/:id", ctx.Delete) | |
private.GET("/sub_categories", ctx.List) | |
private.GET("/sub_categories/:id", ctx.Get) | |
private.POST("/sub_categories", ctx.Create) | |
private.PUT("/sub_categories/:id", ctx.Update) | |
private.DELETE("/sub_categories/:id", ctx.Delete) | |
//DB - All databases table need equal model name and router. Model.User = users(DB) and router too (users). | |
//create table categories() | |
//create table sub_categories() | |
//create table users() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment