mirror of https://github.com/go-gorm/gorm.git
Merge branch 'adamar-master'
This commit is contained in:
commit
b8976ab20f
36
callback.go
36
callback.go
|
@ -9,10 +9,10 @@ type callback struct {
|
||||||
updates []*func(scope *Scope)
|
updates []*func(scope *Scope)
|
||||||
deletes []*func(scope *Scope)
|
deletes []*func(scope *Scope)
|
||||||
queries []*func(scope *Scope)
|
queries []*func(scope *Scope)
|
||||||
processors []*callback_processor
|
processors []*callbackProcessor
|
||||||
}
|
}
|
||||||
|
|
||||||
type callback_processor struct {
|
type callbackProcessor struct {
|
||||||
name string
|
name string
|
||||||
before string
|
before string
|
||||||
after string
|
after string
|
||||||
|
@ -23,8 +23,8 @@ type callback_processor struct {
|
||||||
callback *callback
|
callback *callback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *callback) addProcessor(typ string) *callback_processor {
|
func (c *callback) addProcessor(typ string) *callbackProcessor {
|
||||||
cp := &callback_processor{typ: typ, callback: c}
|
cp := &callbackProcessor{typ: typ, callback: c}
|
||||||
c.processors = append(c.processors, cp)
|
c.processors = append(c.processors, cp)
|
||||||
return cp
|
return cp
|
||||||
}
|
}
|
||||||
|
@ -33,46 +33,46 @@ func (c *callback) clone() *callback {
|
||||||
return &callback{processors: c.processors}
|
return &callback{processors: c.processors}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *callback) Create() *callback_processor {
|
func (c *callback) Create() *callbackProcessor {
|
||||||
return c.addProcessor("create")
|
return c.addProcessor("create")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *callback) Update() *callback_processor {
|
func (c *callback) Update() *callbackProcessor {
|
||||||
return c.addProcessor("update")
|
return c.addProcessor("update")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *callback) Delete() *callback_processor {
|
func (c *callback) Delete() *callbackProcessor {
|
||||||
return c.addProcessor("delete")
|
return c.addProcessor("delete")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *callback) Query() *callback_processor {
|
func (c *callback) Query() *callbackProcessor {
|
||||||
return c.addProcessor("query")
|
return c.addProcessor("query")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *callback_processor) Before(name string) *callback_processor {
|
func (cp *callbackProcessor) Before(name string) *callbackProcessor {
|
||||||
cp.before = name
|
cp.before = name
|
||||||
return cp
|
return cp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *callback_processor) After(name string) *callback_processor {
|
func (cp *callbackProcessor) After(name string) *callbackProcessor {
|
||||||
cp.after = name
|
cp.after = name
|
||||||
return cp
|
return cp
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *callback_processor) Register(name string, fc func(scope *Scope)) {
|
func (cp *callbackProcessor) Register(name string, fc func(scope *Scope)) {
|
||||||
cp.name = name
|
cp.name = name
|
||||||
cp.processor = &fc
|
cp.processor = &fc
|
||||||
cp.callback.sort()
|
cp.callback.sort()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *callback_processor) Remove(name string) {
|
func (cp *callbackProcessor) Remove(name string) {
|
||||||
fmt.Printf("[info] removing callback `%v` from %v\n", name, fileWithLineNum())
|
fmt.Printf("[info] removing callback `%v` from %v\n", name, fileWithLineNum())
|
||||||
cp.name = name
|
cp.name = name
|
||||||
cp.remove = true
|
cp.remove = true
|
||||||
cp.callback.sort()
|
cp.callback.sort()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *callback_processor) Replace(name string, fc func(scope *Scope)) {
|
func (cp *callbackProcessor) Replace(name string, fc func(scope *Scope)) {
|
||||||
fmt.Printf("[info] replacing callback `%v` from %v\n", name, fileWithLineNum())
|
fmt.Printf("[info] replacing callback `%v` from %v\n", name, fileWithLineNum())
|
||||||
cp.name = name
|
cp.name = name
|
||||||
cp.processor = &fc
|
cp.processor = &fc
|
||||||
|
@ -89,8 +89,8 @@ func getRIndex(strs []string, str string) int {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func sortProcessors(cps []*callback_processor) []*func(scope *Scope) {
|
func sortProcessors(cps []*callbackProcessor) []*func(scope *Scope) {
|
||||||
var sortCallbackProcessor func(c *callback_processor)
|
var sortCallbackProcessor func(c *callbackProcessor)
|
||||||
var names, sortedNames = []string{}, []string{}
|
var names, sortedNames = []string{}, []string{}
|
||||||
|
|
||||||
for _, cp := range cps {
|
for _, cp := range cps {
|
||||||
|
@ -102,7 +102,7 @@ func sortProcessors(cps []*callback_processor) []*func(scope *Scope) {
|
||||||
names = append(names, cp.name)
|
names = append(names, cp.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
sortCallbackProcessor = func(c *callback_processor) {
|
sortCallbackProcessor = func(c *callbackProcessor) {
|
||||||
if getRIndex(sortedNames, c.name) > -1 {
|
if getRIndex(sortedNames, c.name) > -1 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ func sortProcessors(cps []*callback_processor) []*func(scope *Scope) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *callback) sort() {
|
func (c *callback) sort() {
|
||||||
creates, updates, deletes, queries := []*callback_processor{}, []*callback_processor{}, []*callback_processor{}, []*callback_processor{}
|
creates, updates, deletes, queries := []*callbackProcessor{}, []*callbackProcessor{}, []*callbackProcessor{}, []*callbackProcessor{}
|
||||||
|
|
||||||
for _, processor := range c.processors {
|
for _, processor := range c.processors {
|
||||||
switch processor.typ {
|
switch processor.typ {
|
||||||
|
@ -183,4 +183,4 @@ func (c *callback) sort() {
|
||||||
c.queries = sortProcessors(queries)
|
c.queries = sortProcessors(queries)
|
||||||
}
|
}
|
||||||
|
|
||||||
var DefaultCallback = &callback{processors: []*callback_processor{}}
|
var DefaultCallback = &callback{processors: []*callbackProcessor{}}
|
||||||
|
|
|
@ -50,7 +50,7 @@ func Query(scope *Scope) {
|
||||||
columns, _ := rows.Columns()
|
columns, _ := rows.Columns()
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
scope.db.RowsAffected += 1
|
scope.db.RowsAffected++
|
||||||
|
|
||||||
anyRecordFound = true
|
anyRecordFound = true
|
||||||
elem := dest
|
elem := dest
|
||||||
|
|
|
@ -16,97 +16,97 @@ func equalFuncs(funcs []*func(s *Scope), fnames []string) bool {
|
||||||
return reflect.DeepEqual(names, fnames)
|
return reflect.DeepEqual(names, fnames)
|
||||||
}
|
}
|
||||||
|
|
||||||
func create(s *Scope) {}
|
func create(s *Scope) {}
|
||||||
func before_create1(s *Scope) {}
|
func beforeCreate1(s *Scope) {}
|
||||||
func before_create2(s *Scope) {}
|
func beforeCreate2(s *Scope) {}
|
||||||
func after_create1(s *Scope) {}
|
func afterCreate1(s *Scope) {}
|
||||||
func after_create2(s *Scope) {}
|
func afterCreate2(s *Scope) {}
|
||||||
|
|
||||||
func TestRegisterCallback(t *testing.T) {
|
func TestRegisterCallback(t *testing.T) {
|
||||||
var callback = &callback{processors: []*callback_processor{}}
|
var callback = &callback{processors: []*callbackProcessor{}}
|
||||||
|
|
||||||
callback.Create().Register("before_create1", before_create1)
|
callback.Create().Register("before_create1", beforeCreate1)
|
||||||
callback.Create().Register("before_create2", before_create2)
|
callback.Create().Register("before_create2", beforeCreate2)
|
||||||
callback.Create().Register("create", create)
|
callback.Create().Register("create", create)
|
||||||
callback.Create().Register("after_create1", after_create1)
|
callback.Create().Register("after_create1", afterCreate1)
|
||||||
callback.Create().Register("after_create2", after_create2)
|
callback.Create().Register("after_create2", afterCreate2)
|
||||||
|
|
||||||
if !equalFuncs(callback.creates, []string{"before_create1", "before_create2", "create", "after_create1", "after_create2"}) {
|
if !equalFuncs(callback.creates, []string{"beforeCreate1", "beforeCreate2", "create", "afterCreate1", "afterCreate2"}) {
|
||||||
t.Errorf("register callback")
|
t.Errorf("register callback")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRegisterCallbackWithOrder(t *testing.T) {
|
func TestRegisterCallbackWithOrder(t *testing.T) {
|
||||||
var callback1 = &callback{processors: []*callback_processor{}}
|
var callback1 = &callback{processors: []*callbackProcessor{}}
|
||||||
callback1.Create().Register("before_create1", before_create1)
|
callback1.Create().Register("before_create1", beforeCreate1)
|
||||||
callback1.Create().Register("create", create)
|
callback1.Create().Register("create", create)
|
||||||
callback1.Create().Register("after_create1", after_create1)
|
callback1.Create().Register("after_create1", afterCreate1)
|
||||||
callback1.Create().Before("after_create1").Register("after_create2", after_create2)
|
callback1.Create().Before("after_create1").Register("after_create2", afterCreate2)
|
||||||
if !equalFuncs(callback1.creates, []string{"before_create1", "create", "after_create2", "after_create1"}) {
|
if !equalFuncs(callback1.creates, []string{"beforeCreate1", "create", "afterCreate2", "afterCreate1"}) {
|
||||||
t.Errorf("register callback with order")
|
t.Errorf("register callback with order")
|
||||||
}
|
}
|
||||||
|
|
||||||
var callback2 = &callback{processors: []*callback_processor{}}
|
var callback2 = &callback{processors: []*callbackProcessor{}}
|
||||||
|
|
||||||
callback2.Update().Register("create", create)
|
callback2.Update().Register("create", create)
|
||||||
callback2.Update().Before("create").Register("before_create1", before_create1)
|
callback2.Update().Before("create").Register("before_create1", beforeCreate1)
|
||||||
callback2.Update().After("after_create2").Register("after_create1", after_create1)
|
callback2.Update().After("after_create2").Register("after_create1", afterCreate1)
|
||||||
callback2.Update().Before("before_create1").Register("before_create2", before_create2)
|
callback2.Update().Before("before_create1").Register("before_create2", beforeCreate2)
|
||||||
callback2.Update().Register("after_create2", after_create2)
|
callback2.Update().Register("after_create2", afterCreate2)
|
||||||
|
|
||||||
if !equalFuncs(callback2.updates, []string{"before_create2", "before_create1", "create", "after_create2", "after_create1"}) {
|
if !equalFuncs(callback2.updates, []string{"beforeCreate2", "beforeCreate1", "create", "afterCreate2", "afterCreate1"}) {
|
||||||
t.Errorf("register callback with order")
|
t.Errorf("register callback with order")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRegisterCallbackWithComplexOrder(t *testing.T) {
|
func TestRegisterCallbackWithComplexOrder(t *testing.T) {
|
||||||
var callback1 = &callback{processors: []*callback_processor{}}
|
var callback1 = &callback{processors: []*callbackProcessor{}}
|
||||||
|
|
||||||
callback1.Query().Before("after_create1").After("before_create1").Register("create", create)
|
callback1.Query().Before("after_create1").After("before_create1").Register("create", create)
|
||||||
callback1.Query().Register("before_create1", before_create1)
|
callback1.Query().Register("before_create1", beforeCreate1)
|
||||||
callback1.Query().Register("after_create1", after_create1)
|
callback1.Query().Register("after_create1", afterCreate1)
|
||||||
|
|
||||||
if !equalFuncs(callback1.queries, []string{"before_create1", "create", "after_create1"}) {
|
if !equalFuncs(callback1.queries, []string{"beforeCreate1", "create", "afterCreate1"}) {
|
||||||
t.Errorf("register callback with order")
|
t.Errorf("register callback with order")
|
||||||
}
|
}
|
||||||
|
|
||||||
var callback2 = &callback{processors: []*callback_processor{}}
|
var callback2 = &callback{processors: []*callbackProcessor{}}
|
||||||
|
|
||||||
callback2.Delete().Before("after_create1").After("before_create1").Register("create", create)
|
callback2.Delete().Before("after_create1").After("before_create1").Register("create", create)
|
||||||
callback2.Delete().Before("create").Register("before_create1", before_create1)
|
callback2.Delete().Before("create").Register("before_create1", beforeCreate1)
|
||||||
callback2.Delete().After("before_create1").Register("before_create2", before_create2)
|
callback2.Delete().After("before_create1").Register("before_create2", beforeCreate2)
|
||||||
callback2.Delete().Register("after_create1", after_create1)
|
callback2.Delete().Register("after_create1", afterCreate1)
|
||||||
callback2.Delete().After("after_create1").Register("after_create2", after_create2)
|
callback2.Delete().After("after_create1").Register("after_create2", afterCreate2)
|
||||||
|
|
||||||
if !equalFuncs(callback2.deletes, []string{"before_create1", "before_create2", "create", "after_create1", "after_create2"}) {
|
if !equalFuncs(callback2.deletes, []string{"beforeCreate1", "beforeCreate2", "create", "afterCreate1", "afterCreate2"}) {
|
||||||
t.Errorf("register callback with order")
|
t.Errorf("register callback with order")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func replace_create(s *Scope) {}
|
func replaceCreate(s *Scope) {}
|
||||||
|
|
||||||
func TestReplaceCallback(t *testing.T) {
|
func TestReplaceCallback(t *testing.T) {
|
||||||
var callback = &callback{processors: []*callback_processor{}}
|
var callback = &callback{processors: []*callbackProcessor{}}
|
||||||
|
|
||||||
callback.Create().Before("after_create1").After("before_create1").Register("create", create)
|
callback.Create().Before("after_create1").After("before_create1").Register("create", create)
|
||||||
callback.Create().Register("before_create1", before_create1)
|
callback.Create().Register("before_create1", beforeCreate1)
|
||||||
callback.Create().Register("after_create1", after_create1)
|
callback.Create().Register("after_create1", afterCreate1)
|
||||||
callback.Create().Replace("create", replace_create)
|
callback.Create().Replace("create", replaceCreate)
|
||||||
|
|
||||||
if !equalFuncs(callback.creates, []string{"before_create1", "replace_create", "after_create1"}) {
|
if !equalFuncs(callback.creates, []string{"beforeCreate1", "replaceCreate", "afterCreate1"}) {
|
||||||
t.Errorf("replace callback")
|
t.Errorf("replace callback")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRemoveCallback(t *testing.T) {
|
func TestRemoveCallback(t *testing.T) {
|
||||||
var callback = &callback{processors: []*callback_processor{}}
|
var callback = &callback{processors: []*callbackProcessor{}}
|
||||||
|
|
||||||
callback.Create().Before("after_create1").After("before_create1").Register("create", create)
|
callback.Create().Before("after_create1").After("before_create1").Register("create", create)
|
||||||
callback.Create().Register("before_create1", before_create1)
|
callback.Create().Register("before_create1", beforeCreate1)
|
||||||
callback.Create().Register("after_create1", after_create1)
|
callback.Create().Register("after_create1", afterCreate1)
|
||||||
callback.Create().Remove("create")
|
callback.Create().Remove("create")
|
||||||
|
|
||||||
if !equalFuncs(callback.creates, []string{"before_create1", "after_create1"}) {
|
if !equalFuncs(callback.creates, []string{"beforeCreate1", "afterCreate1"}) {
|
||||||
t.Errorf("remove callback")
|
t.Errorf("remove callback")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ func (s *commonDialect) HasTop() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *commonDialect) SqlTag(value reflect.Value, size int) string {
|
func (s *commonDialect) SqlTag(value reflect.Value, size int) string {
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
return "BOOLEAN"
|
return "BOOLEAN"
|
||||||
|
@ -33,9 +33,8 @@ func (d *commonDialect) SqlTag(value reflect.Value, size int) string {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
if size > 0 && size < 65532 {
|
if size > 0 && size < 65532 {
|
||||||
return fmt.Sprintf("VARCHAR(%d)", size)
|
return fmt.Sprintf("VARCHAR(%d)", size)
|
||||||
} else {
|
|
||||||
return "VARCHAR(65532)"
|
|
||||||
}
|
}
|
||||||
|
return "VARCHAR(65532)"
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if value.Type() == timeType {
|
if value.Type() == timeType {
|
||||||
return "TIMESTAMP"
|
return "TIMESTAMP"
|
||||||
|
@ -44,21 +43,20 @@ func (d *commonDialect) SqlTag(value reflect.Value, size int) string {
|
||||||
if _, ok := value.Interface().([]byte); ok {
|
if _, ok := value.Interface().([]byte); ok {
|
||||||
if size > 0 && size < 65532 {
|
if size > 0 && size < 65532 {
|
||||||
return fmt.Sprintf("BINARY(%d)", size)
|
return fmt.Sprintf("BINARY(%d)", size)
|
||||||
} else {
|
|
||||||
return "BINARY(65532)"
|
|
||||||
}
|
}
|
||||||
|
return "BINARY(65532)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf("invalid sql type %s (%s) for commonDialect", value.Type().Name(), value.Kind().String()))
|
panic(fmt.Sprintf("invalid sql type %s (%s) for commonDialect", value.Type().Name(), value.Kind().String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *commonDialect) PrimaryKeyTag(value reflect.Value, size int) string {
|
func (s *commonDialect) PrimaryKeyTag(value reflect.Value, size int) string {
|
||||||
suffix_str := " NOT NULL PRIMARY KEY"
|
suffix := " NOT NULL PRIMARY KEY"
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
|
||||||
return "INTEGER" + suffix_str
|
return "INTEGER" + suffix
|
||||||
case reflect.Int64, reflect.Uint64:
|
case reflect.Int64, reflect.Uint64:
|
||||||
return "BIGINT" + suffix_str
|
return "BIGINT" + suffix
|
||||||
default:
|
default:
|
||||||
panic("Invalid primary key type")
|
panic("Invalid primary key type")
|
||||||
}
|
}
|
||||||
|
|
10
errors.go
10
errors.go
|
@ -3,9 +3,9 @@ package gorm
|
||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
RecordNotFound = errors.New("Record Not Found")
|
RecordNotFound = errors.New("record not found")
|
||||||
InvalidSql = errors.New("Invalid SQL")
|
InvalidSql = errors.New("invalid sql")
|
||||||
NoNewAttrs = errors.New("No new Attributes")
|
NoNewAttrs = errors.New("no new attributes")
|
||||||
NoValidTransaction = errors.New("No valid transaction")
|
NoValidTransaction = errors.New("no valid transaction")
|
||||||
CantStartTransaction = errors.New("Can't start transaction")
|
CantStartTransaction = errors.New("can't start transaction")
|
||||||
)
|
)
|
||||||
|
|
3
main.go
3
main.go
|
@ -265,9 +265,8 @@ func (s *DB) Save(value interface{}) *DB {
|
||||||
scope := s.clone().NewScope(value)
|
scope := s.clone().NewScope(value)
|
||||||
if scope.PrimaryKeyZero() {
|
if scope.PrimaryKeyZero() {
|
||||||
return scope.callCallbacks(s.parent.callback.creates).db
|
return scope.callCallbacks(s.parent.callback.creates).db
|
||||||
} else {
|
|
||||||
return scope.callCallbacks(s.parent.callback.updates).db
|
|
||||||
}
|
}
|
||||||
|
return scope.callCallbacks(s.parent.callback.updates).db
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DB) Create(value interface{}) *DB {
|
func (s *DB) Create(value interface{}) *DB {
|
||||||
|
|
16
main_test.go
16
main_test.go
|
@ -588,10 +588,10 @@ func BenchmarkGorm(b *testing.B) {
|
||||||
func BenchmarkRawSql(b *testing.B) {
|
func BenchmarkRawSql(b *testing.B) {
|
||||||
DB, _ := sql.Open("postgres", "user=gorm DB.ame=gorm sslmode=disable")
|
DB, _ := sql.Open("postgres", "user=gorm DB.ame=gorm sslmode=disable")
|
||||||
DB.SetMaxIdleConns(10)
|
DB.SetMaxIdleConns(10)
|
||||||
insert_sql := "INSERT INTO emails (user_id,email,user_agent,registered_at,created_at,updated_at) VALUES ($1,$2,$3,$4,$5,$6) RETURNING id"
|
insertSql := "INSERT INTO emails (user_id,email,user_agent,registered_at,created_at,updated_at) VALUES ($1,$2,$3,$4,$5,$6) RETURNING id"
|
||||||
query_sql := "SELECT * FROM emails WHERE email = $1 ORDER BY id LIMIT 1"
|
querySql := "SELECT * FROM emails WHERE email = $1 ORDER BY id LIMIT 1"
|
||||||
update_sql := "UPDATE emails SET email = $1, updated_at = $2 WHERE id = $3"
|
updateSql := "UPDATE emails SET email = $1, updated_at = $2 WHERE id = $3"
|
||||||
delete_sql := "DELETE FROM orders WHERE id = $1"
|
deleteSql := "DELETE FROM orders WHERE id = $1"
|
||||||
|
|
||||||
b.N = 2000
|
b.N = 2000
|
||||||
for x := 0; x < b.N; x++ {
|
for x := 0; x < b.N; x++ {
|
||||||
|
@ -599,13 +599,13 @@ func BenchmarkRawSql(b *testing.B) {
|
||||||
e := strconv.Itoa(x) + "benchmark@example.org"
|
e := strconv.Itoa(x) + "benchmark@example.org"
|
||||||
email := BigEmail{Email: e, UserAgent: "pc", RegisteredAt: time.Now()}
|
email := BigEmail{Email: e, UserAgent: "pc", RegisteredAt: time.Now()}
|
||||||
// Insert
|
// Insert
|
||||||
DB.QueryRow(insert_sql, email.UserId, email.Email, email.UserAgent, email.RegisteredAt, time.Now(), time.Now()).Scan(&id)
|
DB.QueryRow(insertSql, email.UserId, email.Email, email.UserAgent, email.RegisteredAt, time.Now(), time.Now()).Scan(&id)
|
||||||
// Query
|
// Query
|
||||||
rows, _ := DB.Query(query_sql, email.Email)
|
rows, _ := DB.Query(querySql, email.Email)
|
||||||
rows.Close()
|
rows.Close()
|
||||||
// Update
|
// Update
|
||||||
DB.Exec(update_sql, "new-"+e, time.Now(), id)
|
DB.Exec(updateSql, "new-"+e, time.Now(), id)
|
||||||
// Delete
|
// Delete
|
||||||
DB.Exec(delete_sql, id)
|
DB.Exec(deleteSql, id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
14
mssql.go
14
mssql.go
|
@ -20,7 +20,7 @@ func (s *mssql) HasTop() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *mssql) SqlTag(value reflect.Value, size int) string {
|
func (s *mssql) SqlTag(value reflect.Value, size int) string {
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
return "bit"
|
return "bit"
|
||||||
|
@ -33,9 +33,8 @@ func (d *mssql) SqlTag(value reflect.Value, size int) string {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
if size > 0 && size < 65532 {
|
if size > 0 && size < 65532 {
|
||||||
return fmt.Sprintf("nvarchar(%d)", size)
|
return fmt.Sprintf("nvarchar(%d)", size)
|
||||||
} else {
|
|
||||||
return "text"
|
|
||||||
}
|
}
|
||||||
|
return "text"
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if value.Type() == timeType {
|
if value.Type() == timeType {
|
||||||
return "datetime2"
|
return "datetime2"
|
||||||
|
@ -44,21 +43,20 @@ func (d *mssql) SqlTag(value reflect.Value, size int) string {
|
||||||
if _, ok := value.Interface().([]byte); ok {
|
if _, ok := value.Interface().([]byte); ok {
|
||||||
if size > 0 && size < 65532 {
|
if size > 0 && size < 65532 {
|
||||||
return fmt.Sprintf("varchar(%d)", size)
|
return fmt.Sprintf("varchar(%d)", size)
|
||||||
} else {
|
|
||||||
return "text"
|
|
||||||
}
|
}
|
||||||
|
return "text"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf("invalid sql type %s (%s) for mssql", value.Type().Name(), value.Kind().String()))
|
panic(fmt.Sprintf("invalid sql type %s (%s) for mssql", value.Type().Name(), value.Kind().String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mssql) PrimaryKeyTag(value reflect.Value, size int) string {
|
func (s *mssql) PrimaryKeyTag(value reflect.Value, size int) string {
|
||||||
suffix_str := " IDENTITY(1,1) PRIMARY KEY"
|
suffix := " IDENTITY(1,1) PRIMARY KEY"
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
|
||||||
return "int" + suffix_str
|
return "int" + suffix
|
||||||
case reflect.Int64, reflect.Uint64:
|
case reflect.Int64, reflect.Uint64:
|
||||||
return "bigint" + suffix_str
|
return "bigint" + suffix
|
||||||
default:
|
default:
|
||||||
panic("Invalid primary key type")
|
panic("Invalid primary key type")
|
||||||
}
|
}
|
||||||
|
|
14
mysql.go
14
mysql.go
|
@ -20,7 +20,7 @@ func (s *mysql) HasTop() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *mysql) SqlTag(value reflect.Value, size int) string {
|
func (s *mysql) SqlTag(value reflect.Value, size int) string {
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
return "boolean"
|
return "boolean"
|
||||||
|
@ -33,9 +33,8 @@ func (d *mysql) SqlTag(value reflect.Value, size int) string {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
if size > 0 && size < 65532 {
|
if size > 0 && size < 65532 {
|
||||||
return fmt.Sprintf("varchar(%d)", size)
|
return fmt.Sprintf("varchar(%d)", size)
|
||||||
} else {
|
|
||||||
return "longtext"
|
|
||||||
}
|
}
|
||||||
|
return "longtext"
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if value.Type() == timeType {
|
if value.Type() == timeType {
|
||||||
return "timestamp NULL"
|
return "timestamp NULL"
|
||||||
|
@ -44,21 +43,20 @@ func (d *mysql) SqlTag(value reflect.Value, size int) string {
|
||||||
if _, ok := value.Interface().([]byte); ok {
|
if _, ok := value.Interface().([]byte); ok {
|
||||||
if size > 0 && size < 65532 {
|
if size > 0 && size < 65532 {
|
||||||
return fmt.Sprintf("varbinary(%d)", size)
|
return fmt.Sprintf("varbinary(%d)", size)
|
||||||
} else {
|
|
||||||
return "longblob"
|
|
||||||
}
|
}
|
||||||
|
return "longblob"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf("invalid sql type %s (%s) for mysql", value.Type().Name(), value.Kind().String()))
|
panic(fmt.Sprintf("invalid sql type %s (%s) for mysql", value.Type().Name(), value.Kind().String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *mysql) PrimaryKeyTag(value reflect.Value, size int) string {
|
func (s *mysql) PrimaryKeyTag(value reflect.Value, size int) string {
|
||||||
suffix_str := " NOT NULL AUTO_INCREMENT PRIMARY KEY"
|
suffix := " NOT NULL AUTO_INCREMENT PRIMARY KEY"
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
|
||||||
return "int" + suffix_str
|
return "int" + suffix
|
||||||
case reflect.Int64, reflect.Uint64:
|
case reflect.Int64, reflect.Uint64:
|
||||||
return "bigint" + suffix_str
|
return "bigint" + suffix
|
||||||
default:
|
default:
|
||||||
panic("Invalid primary key type")
|
panic("Invalid primary key type")
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ func (s *postgres) HasTop() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *postgres) SqlTag(value reflect.Value, size int) string {
|
func (s *postgres) SqlTag(value reflect.Value, size int) string {
|
||||||
switch value.Kind() {
|
switch value.Kind() {
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
return "boolean"
|
return "boolean"
|
||||||
|
|
91
scope.go
91
scope.go
|
@ -41,7 +41,7 @@ func (db *DB) NewScope(value interface{}) *Scope {
|
||||||
func (scope *Scope) NeedPtr() *Scope {
|
func (scope *Scope) NeedPtr() *Scope {
|
||||||
reflectKind := reflect.ValueOf(scope.Value).Kind()
|
reflectKind := reflect.ValueOf(scope.Value).Kind()
|
||||||
if !((reflectKind == reflect.Invalid) || (reflectKind == reflect.Ptr)) {
|
if !((reflectKind == reflect.Invalid) || (reflectKind == reflect.Ptr)) {
|
||||||
err := errors.New(fmt.Sprintf("%v %v\n", fileWithLineNum(), "using unaddressable value"))
|
err := fmt.Errorf("%v %v\n", fileWithLineNum(), "using unaddressable value")
|
||||||
scope.Err(err)
|
scope.Err(err)
|
||||||
fmt.Printf(err.Error())
|
fmt.Printf(err.Error())
|
||||||
}
|
}
|
||||||
|
@ -125,9 +125,8 @@ func (scope *Scope) PrimaryKeyField() *Field {
|
||||||
func (scope *Scope) PrimaryKey() string {
|
func (scope *Scope) PrimaryKey() string {
|
||||||
if field := scope.PrimaryKeyField(); field != nil {
|
if field := scope.PrimaryKeyField(); field != nil {
|
||||||
return field.DBName
|
return field.DBName
|
||||||
} else {
|
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrimaryKeyZero check the primary key is blank or not
|
// PrimaryKeyZero check the primary key is blank or not
|
||||||
|
@ -139,9 +138,8 @@ func (scope *Scope) PrimaryKeyZero() bool {
|
||||||
func (scope *Scope) PrimaryKeyValue() interface{} {
|
func (scope *Scope) PrimaryKeyValue() interface{} {
|
||||||
if field := scope.PrimaryKeyField(); field != nil {
|
if field := scope.PrimaryKeyField(); field != nil {
|
||||||
return field.Field.Interface()
|
return field.Field.Interface()
|
||||||
} else {
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasColumn to check if has column
|
// HasColumn to check if has column
|
||||||
|
@ -207,7 +205,7 @@ func (scope *Scope) CallMethod(name string) {
|
||||||
case func(s *DB) error:
|
case func(s *DB) error:
|
||||||
scope.Err(f(scope.db.New()))
|
scope.Err(f(scope.db.New()))
|
||||||
default:
|
default:
|
||||||
scope.Err(errors.New(fmt.Sprintf("unsupported function %v", name)))
|
scope.Err(fmt.Errorf("unsupported function %v", name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,53 +232,54 @@ var pluralMapValues = []string{"ches", "sses", "shes", "days", "ies", "xes", "${
|
||||||
func (scope *Scope) TableName() string {
|
func (scope *Scope) TableName() string {
|
||||||
if scope.Search != nil && len(scope.Search.TableName) > 0 {
|
if scope.Search != nil && len(scope.Search.TableName) > 0 {
|
||||||
return scope.Search.TableName
|
return scope.Search.TableName
|
||||||
} else {
|
|
||||||
if scope.Value == nil {
|
|
||||||
scope.Err(errors.New("can't get table name"))
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
data := scope.IndirectValue()
|
|
||||||
if data.Kind() == reflect.Slice {
|
|
||||||
elem := data.Type().Elem()
|
|
||||||
if elem.Kind() == reflect.Ptr {
|
|
||||||
elem = elem.Elem()
|
|
||||||
}
|
|
||||||
data = reflect.New(elem).Elem()
|
|
||||||
}
|
|
||||||
|
|
||||||
if fm := data.MethodByName("TableName"); fm.IsValid() {
|
|
||||||
if v := fm.Call([]reflect.Value{}); len(v) > 0 {
|
|
||||||
if result, ok := v[0].Interface().(string); ok {
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
str := ToSnake(data.Type().Name())
|
|
||||||
|
|
||||||
if scope.db == nil || !scope.db.parent.singularTable {
|
|
||||||
for index, reg := range pluralMapKeys {
|
|
||||||
if reg.MatchString(str) {
|
|
||||||
return reg.ReplaceAllString(str, pluralMapValues[index])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return str
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if scope.Value == nil {
|
||||||
|
scope.Err(errors.New("can't get table name"))
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
data := scope.IndirectValue()
|
||||||
|
if data.Kind() == reflect.Slice {
|
||||||
|
elem := data.Type().Elem()
|
||||||
|
if elem.Kind() == reflect.Ptr {
|
||||||
|
elem = elem.Elem()
|
||||||
|
}
|
||||||
|
data = reflect.New(elem).Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
if fm := data.MethodByName("TableName"); fm.IsValid() {
|
||||||
|
if v := fm.Call([]reflect.Value{}); len(v) > 0 {
|
||||||
|
if result, ok := v[0].Interface().(string); ok {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
str := ToSnake(data.Type().Name())
|
||||||
|
|
||||||
|
if scope.db == nil || !scope.db.parent.singularTable {
|
||||||
|
for index, reg := range pluralMapKeys {
|
||||||
|
if reg.MatchString(str) {
|
||||||
|
return reg.ReplaceAllString(str, pluralMapValues[index])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scope *Scope) QuotedTableName() string {
|
func (scope *Scope) QuotedTableName() string {
|
||||||
if scope.Search != nil && len(scope.Search.TableName) > 0 {
|
if scope.Search != nil && len(scope.Search.TableName) > 0 {
|
||||||
return scope.Search.TableName
|
return scope.Search.TableName
|
||||||
} else {
|
|
||||||
keys := strings.Split(scope.TableName(), ".")
|
|
||||||
for i, v := range keys {
|
|
||||||
keys[i] = scope.Quote(v)
|
|
||||||
}
|
|
||||||
return strings.Join(keys, ".")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keys := strings.Split(scope.TableName(), ".")
|
||||||
|
for i, v := range keys {
|
||||||
|
keys[i] = scope.Quote(v)
|
||||||
|
}
|
||||||
|
return strings.Join(keys, ".")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CombinedConditionSql get combined condition sql
|
// CombinedConditionSql get combined condition sql
|
||||||
|
|
|
@ -215,87 +215,80 @@ func (scope *Scope) whereSql() (sql string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scope) selectSql() string {
|
func (scope *Scope) selectSql() string {
|
||||||
if len(s.Search.Selects) == 0 {
|
if len(scope.Search.Selects) == 0 {
|
||||||
return "*"
|
return "*"
|
||||||
}
|
}
|
||||||
|
|
||||||
var selectQueries []string
|
var selectQueries []string
|
||||||
|
|
||||||
for _, clause := range s.Search.Selects {
|
for _, clause := range scope.Search.Selects {
|
||||||
selectQueries = append(selectQueries, s.buildSelectQuery(clause))
|
selectQueries = append(selectQueries, scope.buildSelectQuery(clause))
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(selectQueries, ", ")
|
return strings.Join(selectQueries, ", ")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scope) orderSql() string {
|
func (scope *Scope) orderSql() string {
|
||||||
if len(s.Search.Orders) == 0 {
|
if len(scope.Search.Orders) == 0 {
|
||||||
return ""
|
return ""
|
||||||
} else {
|
|
||||||
return " ORDER BY " + strings.Join(s.Search.Orders, ",")
|
|
||||||
}
|
}
|
||||||
|
return " ORDER BY " + strings.Join(scope.Search.Orders, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scope) limitSql() string {
|
func (scope *Scope) limitSql() string {
|
||||||
if !s.Dialect().HasTop() {
|
if !scope.Dialect().HasTop() {
|
||||||
if len(s.Search.Limit) == 0 {
|
if len(scope.Search.Limit) == 0 {
|
||||||
return ""
|
return ""
|
||||||
} else {
|
|
||||||
return " LIMIT " + s.Search.Limit
|
|
||||||
}
|
}
|
||||||
} else {
|
return " LIMIT " + scope.Search.Limit
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scope) topSql() string {
|
func (scope *Scope) topSql() string {
|
||||||
if s.Dialect().HasTop() && len(s.Search.Offset) == 0 {
|
if scope.Dialect().HasTop() && len(scope.Search.Offset) == 0 {
|
||||||
if len(s.Search.Limit) == 0 {
|
if len(scope.Search.Limit) == 0 {
|
||||||
return ""
|
return ""
|
||||||
} else {
|
|
||||||
return " TOP(" + s.Search.Limit + ")"
|
|
||||||
}
|
}
|
||||||
} else {
|
return " TOP(" + scope.Search.Limit + ")"
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scope) offsetSql() string {
|
func (scope *Scope) offsetSql() string {
|
||||||
if len(s.Search.Offset) == 0 {
|
if len(scope.Search.Offset) == 0 {
|
||||||
return ""
|
return ""
|
||||||
} else {
|
}
|
||||||
if s.Dialect().HasTop() {
|
|
||||||
sql := " OFFSET " + s.Search.Offset + " ROW "
|
if scope.Dialect().HasTop() {
|
||||||
if len(s.Search.Limit) > 0 {
|
sql := " OFFSET " + scope.Search.Offset + " ROW "
|
||||||
sql += "FETCH NEXT " + s.Search.Limit + " ROWS ONLY"
|
if len(scope.Search.Limit) > 0 {
|
||||||
}
|
sql += "FETCH NEXT " + scope.Search.Limit + " ROWS ONLY"
|
||||||
return sql
|
|
||||||
} else {
|
|
||||||
return " OFFSET " + s.Search.Offset
|
|
||||||
}
|
}
|
||||||
|
return sql
|
||||||
}
|
}
|
||||||
|
return " OFFSET " + scope.Search.Offset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scope) groupSql() string {
|
func (scope *Scope) groupSql() string {
|
||||||
if len(s.Search.Group) == 0 {
|
if len(scope.Search.Group) == 0 {
|
||||||
return ""
|
return ""
|
||||||
} else {
|
|
||||||
return " GROUP BY " + s.Search.Group
|
|
||||||
}
|
}
|
||||||
|
return " GROUP BY " + scope.Search.Group
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scope) havingSql() string {
|
func (scope *Scope) havingSql() string {
|
||||||
if s.Search.HavingCondition == nil {
|
if scope.Search.HavingCondition == nil {
|
||||||
return ""
|
return ""
|
||||||
} else {
|
|
||||||
return " HAVING " + s.buildWhereCondition(s.Search.HavingCondition)
|
|
||||||
}
|
}
|
||||||
|
return " HAVING " + scope.buildWhereCondition(scope.Search.HavingCondition)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scope) joinsSql() string {
|
func (scope *Scope) joinsSql() string {
|
||||||
return s.Search.Joins + " "
|
return scope.Search.Joins + " "
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scope *Scope) prepareQuerySql() {
|
func (scope *Scope) prepareQuerySql() {
|
||||||
|
@ -479,9 +472,9 @@ func (scope *Scope) typeName() string {
|
||||||
value := scope.IndirectValue()
|
value := scope.IndirectValue()
|
||||||
if value.Kind() == reflect.Slice {
|
if value.Kind() == reflect.Slice {
|
||||||
return value.Type().Elem().Name()
|
return value.Type().Elem().Name()
|
||||||
} else {
|
|
||||||
return value.Type().Name()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return value.Type().Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scope *Scope) related(value interface{}, foreignKeys ...string) *Scope {
|
func (scope *Scope) related(value interface{}, foreignKeys ...string) *Scope {
|
||||||
|
@ -634,9 +627,9 @@ func (scope *Scope) addIndex(unique bool, indexName string, column ...string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (scope *Scope) addForeignKey(field string, dest string, onDelete string, onUpdate string) {
|
func (scope *Scope) addForeignKey(field string, dest string, onDelete string, onUpdate string) {
|
||||||
var table string = scope.TableName()
|
var table = scope.TableName()
|
||||||
var keyName string = fmt.Sprintf("%s_%s_foreign", table, field)
|
var keyName = fmt.Sprintf("%s_%s_foreign", table, field)
|
||||||
var query string = `
|
var query = `
|
||||||
ALTER TABLE %s
|
ALTER TABLE %s
|
||||||
ADD CONSTRAINT %s
|
ADD CONSTRAINT %s
|
||||||
FOREIGN KEY (%s)
|
FOREIGN KEY (%s)
|
||||||
|
|
|
@ -32,9 +32,8 @@ func (s *sqlite3) SqlTag(value reflect.Value, size int) string {
|
||||||
case reflect.String:
|
case reflect.String:
|
||||||
if size > 0 && size < 65532 {
|
if size > 0 && size < 65532 {
|
||||||
return fmt.Sprintf("varchar(%d)", size)
|
return fmt.Sprintf("varchar(%d)", size)
|
||||||
} else {
|
|
||||||
return "text"
|
|
||||||
}
|
}
|
||||||
|
return "text"
|
||||||
case reflect.Struct:
|
case reflect.Struct:
|
||||||
if value.Type() == timeType {
|
if value.Type() == timeType {
|
||||||
return "datetime"
|
return "datetime"
|
||||||
|
|
2
utils.go
2
utils.go
|
@ -34,7 +34,7 @@ func FieldValueByName(name string, value interface{}) (i interface{}, err error)
|
||||||
if field := data.FieldByName(name); field.IsValid() {
|
if field := data.FieldByName(name); field.IsValid() {
|
||||||
i = field.Interface()
|
i = field.Interface()
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New(fmt.Sprintf("struct has no field with name %s", name))
|
return nil, fmt.Errorf("struct has no field with name %s", name)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New("value must be of kind struct")
|
return nil, errors.New("value must be of kind struct")
|
||||||
|
|
Loading…
Reference in New Issue