add database/orm/reform example

This commit is contained in:
Gerasimos (Makis) Maropoulos 2020-08-01 03:46:51 +03:00
parent eacbcea653
commit acf058b006
No known key found for this signature in database
GPG Key ID: 5DBE766BD26A54E7
10 changed files with 339 additions and 2 deletions

View File

@ -153,6 +153,8 @@ Prior to this version the `iris.Context` was the only one dependency that has be
| [http.ResponseWriter](https://golang.org/pkg/net/http/#ResponseWriter) | `ctx.ResponseWriter()` | | [http.ResponseWriter](https://golang.org/pkg/net/http/#ResponseWriter) | `ctx.ResponseWriter()` |
| [http.Header](https://golang.org/pkg/net/http/#Header) | `ctx.Request().Header` | | [http.Header](https://golang.org/pkg/net/http/#Header) | `ctx.Request().Header` |
| [time.Time](https://golang.org/pkg/time/#Time) | `time.Now()` | | [time.Time](https://golang.org/pkg/time/#Time) | `time.Now()` |
| [golog.Logger](https://pkg.go.dev/github.com/kataras/golog) | Iris Logger |
| [net.IP](https://golang.org/pkg/net/#IP) | `net.ParseIP(ctx.RemoteAddr())` |
| `string`, | | | `string`, | |
| `int, int8, int16, int32, int64`, | | | `int, int8, int16, int32, int64`, | |
| `uint, uint8, uint16, uint32, uint64`, | | | `uint, uint8, uint16, uint32, uint64`, | |

View File

@ -9,6 +9,7 @@
* [MongoDB](database/mongodb) * [MongoDB](database/mongodb)
* [Xorm](database/orm/xorm/main.go) * [Xorm](database/orm/xorm/main.go)
* [Gorm](database/orm/gorm/main.go) * [Gorm](database/orm/gorm/main.go)
* [Reform](database/orm/reform/main.go)
* HTTP Server * HTTP Server
* [HOST:PORT](http-server/listen-addr/main.go) * [HOST:PORT](http-server/listen-addr/main.go)
* [Public Test Domain](http-server/listen-addr-public/main.go) * [Public Test Domain](http-server/listen-addr-public/main.go)

View File

@ -0,0 +1,47 @@
package controllers
import (
"net"
"time"
"myapp/models"
"github.com/kataras/golog"
"gopkg.in/reform.v1"
)
// PersonController is the model.Person's web controller.
type PersonController struct {
DB *reform.DB
// Logger and IP fields are automatically binded by the framework.
Logger *golog.Logger // binds to the application's logger.
IP net.IP // binds to the client's IP.
}
// Get handles
// GET /persons
func (c *PersonController) Get() ([]reform.Struct, error) {
return c.DB.SelectAllFrom(models.PersonTable, "")
}
// GetBy handles
// GET /persons/{ID}
func (c *PersonController) GetBy(id int32) (reform.Record, error) {
return c.DB.FindByPrimaryKeyFrom(models.PersonTable, id)
}
// Post handles
// POST /persons with JSON request body of model.Person.
func (c *PersonController) Post(p *models.Person) int {
p.CreatedAt = time.Now()
if err := c.DB.Save(p); err != nil {
c.Logger.Errorf("[%s] create person: %v", c.IP.String(), err)
return 500 // iris.StatusInternalServerError
}
c.Logger.Debugf("[%s] create person [%s] succeed", c.IP.String(), p.Name)
return 201 // iris.StatusCreated
}

View File

@ -0,0 +1,11 @@
module myapp
go 1.14
require (
github.com/kataras/iris/v12 v12.1.8
github.com/mattn/go-sqlite3 v1.14.0
gopkg.in/reform.v1 v1.4.0
)
replace github.com/kataras/iris/v12 => ../../../../

View File

@ -0,0 +1,50 @@
package main
/*
$ go get gopkg.in/reform.v1/reform
$ go generate ./models
$ go run .
Read more at: https://github.com/go-reform/reform
*/
import (
"database/sql"
"myapp/controllers"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/mvc"
_ "github.com/mattn/go-sqlite3"
"gopkg.in/reform.v1"
"gopkg.in/reform.v1/dialects/sqlite3"
)
func main() {
app := iris.New()
app.Logger().SetLevel("debug")
sqlDB, err := sql.Open("sqlite3", "./myapp.db")
if err != nil {
panic(err)
}
defer sqlDB.Close()
sqlStmt := `
drop table people;
create table people (id integer not null primary key, name text, email text, created_at datetime not null, updated_at datetime null);
delete from people;
`
_, err = sqlDB.Exec(sqlStmt)
if err != nil {
panic(err)
}
db := reform.NewDB(sqlDB, sqlite3.Dialect, reform.NewPrintfLogger(app.Logger().Debugf))
mvcApp := mvc.New(app.Party("/persons"))
mvcApp.Register(db)
mvcApp.Handle(new(controllers.PersonController))
app.Listen(":8080")
}

View File

@ -0,0 +1,13 @@
//go:generate reform
package models
import "time"
//reform:people
type Person struct {
ID int32 `reform:"id,pk" json:"id"`
Name string `reform:"name" json:"name"`
Email *string `reform:"email" json:"email"`
CreatedAt time.Time `reform:"created_at" json:"created_at"`
UpdatedAt *time.Time `reform:"updated_at" json:"updated_at"`
}

View File

@ -0,0 +1,136 @@
// Code generated by gopkg.in/reform.v1. DO NOT EDIT.
package models
import (
"fmt"
"strings"
"gopkg.in/reform.v1"
"gopkg.in/reform.v1/parse"
)
type personTableType struct {
s parse.StructInfo
z []interface{}
}
// Schema returns a schema name in SQL database ("").
func (v *personTableType) Schema() string {
return v.s.SQLSchema
}
// Name returns a view or table name in SQL database ("people").
func (v *personTableType) Name() string {
return v.s.SQLName
}
// Columns returns a new slice of column names for that view or table in SQL database.
func (v *personTableType) Columns() []string {
return []string{"id", "name", "email", "created_at", "updated_at"}
}
// NewStruct makes a new struct for that view or table.
func (v *personTableType) NewStruct() reform.Struct {
return new(Person)
}
// NewRecord makes a new record for that table.
func (v *personTableType) NewRecord() reform.Record {
return new(Person)
}
// PKColumnIndex returns an index of primary key column for that table in SQL database.
func (v *personTableType) PKColumnIndex() uint {
return uint(v.s.PKFieldIndex)
}
// PersonTable represents people view or table in SQL database.
var PersonTable = &personTableType{
s: parse.StructInfo{Type: "Person", SQLSchema: "", SQLName: "people", Fields: []parse.FieldInfo{{Name: "ID", Type: "int32", Column: "id"}, {Name: "Name", Type: "string", Column: "name"}, {Name: "Email", Type: "*string", Column: "email"}, {Name: "CreatedAt", Type: "time.Time", Column: "created_at"}, {Name: "UpdatedAt", Type: "*time.Time", Column: "updated_at"}}, PKFieldIndex: 0},
z: new(Person).Values(),
}
// String returns a string representation of this struct or record.
func (s Person) String() string {
res := make([]string, 5)
res[0] = "ID: " + reform.Inspect(s.ID, true)
res[1] = "Name: " + reform.Inspect(s.Name, true)
res[2] = "Email: " + reform.Inspect(s.Email, true)
res[3] = "CreatedAt: " + reform.Inspect(s.CreatedAt, true)
res[4] = "UpdatedAt: " + reform.Inspect(s.UpdatedAt, true)
return strings.Join(res, ", ")
}
// Values returns a slice of struct or record field values.
// Returned interface{} values are never untyped nils.
func (s *Person) Values() []interface{} {
return []interface{}{
s.ID,
s.Name,
s.Email,
s.CreatedAt,
s.UpdatedAt,
}
}
// Pointers returns a slice of pointers to struct or record fields.
// Returned interface{} values are never untyped nils.
func (s *Person) Pointers() []interface{} {
return []interface{}{
&s.ID,
&s.Name,
&s.Email,
&s.CreatedAt,
&s.UpdatedAt,
}
}
// View returns View object for that struct.
func (s *Person) View() reform.View {
return PersonTable
}
// Table returns Table object for that record.
func (s *Person) Table() reform.Table {
return PersonTable
}
// PKValue returns a value of primary key for that record.
// Returned interface{} value is never untyped nil.
func (s *Person) PKValue() interface{} {
return s.ID
}
// PKPointer returns a pointer to primary key field for that record.
// Returned interface{} value is never untyped nil.
func (s *Person) PKPointer() interface{} {
return &s.ID
}
// HasPK returns true if record has non-zero primary key set, false otherwise.
func (s *Person) HasPK() bool {
return s.ID != PersonTable.z[PersonTable.s.PKFieldIndex]
}
// SetPK sets record primary key.
func (s *Person) SetPK(pk interface{}) {
if i64, ok := pk.(int64); ok {
s.ID = int32(i64)
} else {
s.ID = pk.(int32)
}
}
// check interfaces
var (
_ reform.View = PersonTable
_ reform.Struct = (*Person)(nil)
_ reform.Table = PersonTable
_ reform.Record = (*Person)(nil)
_ fmt.Stringer = (*Person)(nil)
)
func init() {
parse.AssertUpToDate(&PersonTable.s, new(Person))
}

View File

@ -0,0 +1,58 @@
{
"info": {
"_postman_id": "6b66000d-9c04-4d0a-b55c-8a493bf59015",
"name": "iris-reform-example",
"description": "Example API calls for iris reform example.",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "http://localhost:8080/persons",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"name\": \"John\",\r\n \"email\": \"example@example.com\"\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "http://localhost:8080/persons",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"persons"
]
}
},
"response": []
},
{
"name": "http://localhost:8080/persons",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://localhost:8080/persons",
"protocol": "http",
"host": [
"localhost"
],
"port": "8080",
"path": [
"persons"
]
}
},
"response": []
}
],
"protocolProfileBehavior": {}
}

View File

@ -3,12 +3,15 @@ package hero
import ( import (
stdContext "context" stdContext "context"
"errors" "errors"
"net"
"net/http" "net/http"
"reflect" "reflect"
"time" "time"
"github.com/kataras/iris/v12/context" "github.com/kataras/iris/v12/context"
"github.com/kataras/iris/v12/sessions" "github.com/kataras/iris/v12/sessions"
"github.com/kataras/golog"
) )
// Default is the default container value which can be used for dependencies share. // Default is the default container value which can be used for dependencies share.
@ -57,6 +60,10 @@ var BuiltinDependencies = []*Dependency{
return session return session
}).Explicitly(), }).Explicitly(),
// application's logger.
NewDependency(func(ctx *context.Context) *golog.Logger {
return ctx.Application().Logger()
}).Explicitly(),
// time.Time to time.Now dependency. // time.Time to time.Now dependency.
NewDependency(func(ctx *context.Context) time.Time { NewDependency(func(ctx *context.Context) time.Time {
return time.Now() return time.Now()
@ -73,6 +80,10 @@ var BuiltinDependencies = []*Dependency{
NewDependency(func(ctx *context.Context) http.Header { NewDependency(func(ctx *context.Context) http.Header {
return ctx.Request().Header return ctx.Request().Header
}).Explicitly(), }).Explicitly(),
// Client IP.
NewDependency(func(ctx *context.Context) net.IP {
return net.ParseIP(ctx.RemoteAddr())
}).Explicitly(),
// payload and param bindings are dynamically allocated and declared at the end of the `binding` source file. // payload and param bindings are dynamically allocated and declared at the end of the `binding` source file.
} }

View File

@ -1,6 +1,7 @@
package hero package hero
import ( import (
"net"
"reflect" "reflect"
"github.com/kataras/iris/v12/context" "github.com/kataras/iris/v12/context"
@ -41,9 +42,12 @@ func isFunc(kindable interface{ Kind() reflect.Kind }) bool {
return kindable.Kind() == reflect.Func return kindable.Kind() == reflect.Func
} }
var inputTyp = reflect.TypeOf((*Input)(nil)) var (
inputTyp = reflect.TypeOf((*Input)(nil))
errTyp = reflect.TypeOf((*error)(nil)).Elem()
var errTyp = reflect.TypeOf((*error)(nil)).Elem() ipTyp = reflect.TypeOf(net.IP{})
)
// isError returns true if "typ" is type of `error`. // isError returns true if "typ" is type of `error`.
func isError(typ reflect.Type) bool { func isError(typ reflect.Type) bool {
@ -221,6 +225,10 @@ func isZero(v reflect.Value) bool {
return false return false
} }
if v.Type() == ipTyp {
return len(v.Interface().(net.IP)) == 0
}
zero := reflect.Zero(v.Type()) zero := reflect.Zero(v.Type())
return v.Interface() == zero.Interface() return v.Interface() == zero.Interface()
} }