merge from develop; added reverse tool
This commit is contained in:
commit
e8ed91be2b
67
base_test.go
67
base_test.go
|
@ -3,6 +3,7 @@ package xorm
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -98,7 +99,7 @@ func insert(engine *Engine, t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func query(engine *Engine, t *testing.T) {
|
func testQuery(engine *Engine, t *testing.T) {
|
||||||
sql := "select * from userinfo"
|
sql := "select * from userinfo"
|
||||||
results, err := engine.Query(sql)
|
results, err := engine.Query(sql)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -163,6 +164,19 @@ func insertMulti(engine *Engine, t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
users2 := []*Userinfo{
|
||||||
|
&Userinfo{Username: "1xlw", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||||
|
&Userinfo{Username: "1xlw2", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||||
|
&Userinfo{Username: "1xlw11", Departname: "dev", Alias: "lunny2", Created: time.Now()},
|
||||||
|
&Userinfo{Username: "1xlw22", Departname: "dev", Alias: "lunny3", Created: time.Now()},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = engine.Insert(&users2)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func insertTwoTable(engine *Engine, t *testing.T) {
|
func insertTwoTable(engine *Engine, t *testing.T) {
|
||||||
|
@ -1018,6 +1032,18 @@ func testIndexAndUnique(engine *Engine, t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
//panic(err)
|
//panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = engine.CreateIndexes(&IndexOrUnique{})
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
//panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = engine.CreateUniques(&IndexOrUnique{})
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
//panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type IntId struct {
|
type IntId struct {
|
||||||
|
@ -1042,6 +1068,12 @@ func testIntId(engine *Engine, t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = engine.Insert(&IntId{Name: "test"})
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testInt32Id(engine *Engine, t *testing.T) {
|
func testInt32Id(engine *Engine, t *testing.T) {
|
||||||
|
@ -1056,6 +1088,31 @@ func testInt32Id(engine *Engine, t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err = engine.Insert(&Int32Id{Name: "test"})
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testMetaInfo(engine *Engine, t *testing.T) {
|
||||||
|
tables, err := engine.DBMetas()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, table := range tables {
|
||||||
|
fmt.Println(table.Name)
|
||||||
|
for _, col := range table.Columns {
|
||||||
|
fmt.Println(col.String(engine.dialect))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, index := range table.Indexes {
|
||||||
|
fmt.Println(index.Name, index.Type, strings.Join(index.Cols, ","))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAll(engine *Engine, t *testing.T) {
|
func testAll(engine *Engine, t *testing.T) {
|
||||||
|
@ -1066,7 +1123,7 @@ func testAll(engine *Engine, t *testing.T) {
|
||||||
fmt.Println("-------------- insert --------------")
|
fmt.Println("-------------- insert --------------")
|
||||||
insert(engine, t)
|
insert(engine, t)
|
||||||
fmt.Println("-------------- query --------------")
|
fmt.Println("-------------- query --------------")
|
||||||
query(engine, t)
|
testQuery(engine, t)
|
||||||
fmt.Println("-------------- exec --------------")
|
fmt.Println("-------------- exec --------------")
|
||||||
exec(engine, t)
|
exec(engine, t)
|
||||||
fmt.Println("-------------- insertAutoIncr --------------")
|
fmt.Println("-------------- insertAutoIncr --------------")
|
||||||
|
@ -1132,6 +1189,12 @@ func testAll2(engine *Engine, t *testing.T) {
|
||||||
testCreatedAndUpdated(engine, t)
|
testCreatedAndUpdated(engine, t)
|
||||||
fmt.Println("-------------- testIndexAndUnique --------------")
|
fmt.Println("-------------- testIndexAndUnique --------------")
|
||||||
testIndexAndUnique(engine, t)
|
testIndexAndUnique(engine, t)
|
||||||
|
fmt.Println("-------------- testIntId --------------")
|
||||||
|
//testIntId(engine, t)
|
||||||
|
fmt.Println("-------------- testInt32Id --------------")
|
||||||
|
//testInt32Id(engine, t)
|
||||||
|
fmt.Println("-------------- testMetaInfo --------------")
|
||||||
|
testMetaInfo(engine, t)
|
||||||
fmt.Println("-------------- transaction --------------")
|
fmt.Println("-------------- transaction --------------")
|
||||||
transaction(engine, t)
|
transaction(engine, t)
|
||||||
}
|
}
|
||||||
|
|
139
engine.go
139
engine.go
|
@ -20,7 +20,7 @@ const (
|
||||||
|
|
||||||
// a dialect is a driver's wrapper
|
// a dialect is a driver's wrapper
|
||||||
type dialect interface {
|
type dialect interface {
|
||||||
Init(uri string) error
|
Init(DriverName, DataSourceName string) error
|
||||||
SqlType(t *Column) string
|
SqlType(t *Column) string
|
||||||
SupportInsertMany() bool
|
SupportInsertMany() bool
|
||||||
QuoteStr() string
|
QuoteStr() string
|
||||||
|
@ -31,6 +31,10 @@ type dialect interface {
|
||||||
IndexCheckSql(tableName, idxName string) (string, []interface{})
|
IndexCheckSql(tableName, idxName string) (string, []interface{})
|
||||||
TableCheckSql(tableName string) (string, []interface{})
|
TableCheckSql(tableName string) (string, []interface{})
|
||||||
ColumnCheckSql(tableName, colName string) (string, []interface{})
|
ColumnCheckSql(tableName, colName string) (string, []interface{})
|
||||||
|
|
||||||
|
GetColumns(tableName string) (map[string]*Column, error)
|
||||||
|
GetTables() ([]*Table, error)
|
||||||
|
GetIndexes(tableName string) (map[string]*Index, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Engine struct {
|
type Engine struct {
|
||||||
|
@ -38,7 +42,7 @@ type Engine struct {
|
||||||
TagIdentifier string
|
TagIdentifier string
|
||||||
DriverName string
|
DriverName string
|
||||||
DataSourceName string
|
DataSourceName string
|
||||||
Dialect dialect
|
dialect dialect
|
||||||
Tables map[reflect.Type]*Table
|
Tables map[reflect.Type]*Table
|
||||||
mutex *sync.Mutex
|
mutex *sync.Mutex
|
||||||
ShowSQL bool
|
ShowSQL bool
|
||||||
|
@ -57,28 +61,28 @@ type Engine struct {
|
||||||
// When the return is ture, then engine.Insert(&users) will
|
// When the return is ture, then engine.Insert(&users) will
|
||||||
// generate batch sql and exeute.
|
// generate batch sql and exeute.
|
||||||
func (engine *Engine) SupportInsertMany() bool {
|
func (engine *Engine) SupportInsertMany() bool {
|
||||||
return engine.Dialect.SupportInsertMany()
|
return engine.dialect.SupportInsertMany()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Engine's database use which charactor as quote.
|
// Engine's database use which charactor as quote.
|
||||||
// mysql, sqlite use ` and postgres use "
|
// mysql, sqlite use ` and postgres use "
|
||||||
func (engine *Engine) QuoteStr() string {
|
func (engine *Engine) QuoteStr() string {
|
||||||
return engine.Dialect.QuoteStr()
|
return engine.dialect.QuoteStr()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use QuoteStr quote the string sql
|
// Use QuoteStr quote the string sql
|
||||||
func (engine *Engine) Quote(sql string) string {
|
func (engine *Engine) Quote(sql string) string {
|
||||||
return engine.Dialect.QuoteStr() + sql + engine.Dialect.QuoteStr()
|
return engine.dialect.QuoteStr() + sql + engine.dialect.QuoteStr()
|
||||||
}
|
}
|
||||||
|
|
||||||
// A simple wrapper to dialect's SqlType method
|
// A simple wrapper to dialect's SqlType method
|
||||||
func (engine *Engine) SqlType(c *Column) string {
|
func (engine *Engine) SqlType(c *Column) string {
|
||||||
return engine.Dialect.SqlType(c)
|
return engine.dialect.SqlType(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Database's autoincrement statement
|
// Database's autoincrement statement
|
||||||
func (engine *Engine) AutoIncrStr() string {
|
func (engine *Engine) AutoIncrStr() string {
|
||||||
return engine.Dialect.AutoIncrStr()
|
return engine.dialect.AutoIncrStr()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set engine's pool, the pool default is Go's standard library's connection pool.
|
// Set engine's pool, the pool default is Go's standard library's connection pool.
|
||||||
|
@ -178,6 +182,38 @@ func (engine *Engine) NoAutoTime() *Session {
|
||||||
return session.NoAutoTime()
|
return session.NoAutoTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (engine *Engine) DBMetas() ([]*Table, error) {
|
||||||
|
tables, err := engine.dialect.GetTables()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, table := range tables {
|
||||||
|
cols, err := engine.dialect.GetColumns(table.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
table.Columns = cols
|
||||||
|
|
||||||
|
indexes, err := engine.dialect.GetIndexes(table.Name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
table.Indexes = indexes
|
||||||
|
|
||||||
|
for _, index := range indexes {
|
||||||
|
for _, name := range index.Cols {
|
||||||
|
if col, ok := table.Columns[name]; ok {
|
||||||
|
col.Indexes[index.Name] = true
|
||||||
|
} else {
|
||||||
|
return nil, errors.New("Unkonwn col " + name + " in indexes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tables, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (engine *Engine) Cascade(trueOrFalse ...bool) *Session {
|
func (engine *Engine) Cascade(trueOrFalse ...bool) *Session {
|
||||||
session := engine.NewSession()
|
session := engine.NewSession()
|
||||||
session.IsAutoClose = true
|
session.IsAutoClose = true
|
||||||
|
@ -316,7 +352,7 @@ func (engine *Engine) MapType(t reflect.Type) *Table {
|
||||||
|
|
||||||
if ormTagStr != "" {
|
if ormTagStr != "" {
|
||||||
col = &Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false,
|
col = &Column{FieldName: t.Field(i).Name, Nullable: true, IsPrimaryKey: false,
|
||||||
IsAutoIncrement: false, MapType: TWOSIDES}
|
IsAutoIncrement: false, MapType: TWOSIDES, Indexes: make(map[string]bool)}
|
||||||
tags := strings.Split(ormTagStr, " ")
|
tags := strings.Split(ormTagStr, " ")
|
||||||
|
|
||||||
if len(tags) > 0 {
|
if len(tags) > 0 {
|
||||||
|
@ -335,6 +371,8 @@ func (engine *Engine) MapType(t reflect.Type) *Table {
|
||||||
table.PrimaryKey = parentTable.PrimaryKey
|
table.PrimaryKey = parentTable.PrimaryKey
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
var indexType int
|
||||||
|
var indexName string
|
||||||
for j, key := range tags {
|
for j, key := range tags {
|
||||||
k := strings.ToUpper(key)
|
k := strings.ToUpper(key)
|
||||||
switch {
|
switch {
|
||||||
|
@ -358,37 +396,15 @@ func (engine *Engine) MapType(t reflect.Type) *Table {
|
||||||
/*case strings.HasPrefix(k, "--"):
|
/*case strings.HasPrefix(k, "--"):
|
||||||
col.Comment = k[2:len(k)]*/
|
col.Comment = k[2:len(k)]*/
|
||||||
case strings.HasPrefix(k, "INDEX(") && strings.HasSuffix(k, ")"):
|
case strings.HasPrefix(k, "INDEX(") && strings.HasSuffix(k, ")"):
|
||||||
indexName := k[len("INDEX")+1 : len(k)-1]
|
indexType = IndexType
|
||||||
if index, ok := table.Indexes[indexName]; ok {
|
indexName = k[len("INDEX")+1 : len(k)-1]
|
||||||
index.AddColumn(col)
|
|
||||||
col.Index = index
|
|
||||||
} else {
|
|
||||||
index := NewIndex(indexName, false)
|
|
||||||
index.AddColumn(col)
|
|
||||||
table.AddIndex(index)
|
|
||||||
col.Index = index
|
|
||||||
}
|
|
||||||
case k == "INDEX":
|
case k == "INDEX":
|
||||||
index := NewIndex(col.Name, false)
|
indexType = IndexType
|
||||||
index.AddColumn(col)
|
|
||||||
table.AddIndex(index)
|
|
||||||
col.Index = index
|
|
||||||
case strings.HasPrefix(k, "UNIQUE(") && strings.HasSuffix(k, ")"):
|
case strings.HasPrefix(k, "UNIQUE(") && strings.HasSuffix(k, ")"):
|
||||||
indexName := k[len("UNIQUE")+1 : len(k)-1]
|
indexName = k[len("UNIQUE")+1 : len(k)-1]
|
||||||
if index, ok := table.Indexes[indexName]; ok {
|
indexType = UniqueType
|
||||||
index.AddColumn(col)
|
|
||||||
col.Index = index
|
|
||||||
} else {
|
|
||||||
index := NewIndex(indexName, true)
|
|
||||||
index.AddColumn(col)
|
|
||||||
table.AddIndex(index)
|
|
||||||
col.Index = index
|
|
||||||
}
|
|
||||||
case k == "UNIQUE":
|
case k == "UNIQUE":
|
||||||
index := NewIndex(col.Name, true)
|
indexType = UniqueType
|
||||||
index.AddColumn(col)
|
|
||||||
table.AddIndex(index)
|
|
||||||
col.Index = index
|
|
||||||
case k == "NOTNULL":
|
case k == "NOTNULL":
|
||||||
col.Nullable = false
|
col.Nullable = false
|
||||||
case k == "NOT":
|
case k == "NOT":
|
||||||
|
@ -432,12 +448,39 @@ func (engine *Engine) MapType(t reflect.Type) *Table {
|
||||||
if col.Name == "" {
|
if col.Name == "" {
|
||||||
col.Name = engine.Mapper.Obj2Table(t.Field(i).Name)
|
col.Name = engine.Mapper.Obj2Table(t.Field(i).Name)
|
||||||
}
|
}
|
||||||
|
if indexType == IndexType {
|
||||||
|
if indexName == "" {
|
||||||
|
indexName = col.Name
|
||||||
|
}
|
||||||
|
if index, ok := table.Indexes[indexName]; ok {
|
||||||
|
index.AddColumn(col.Name)
|
||||||
|
col.Indexes[index.Name] = true
|
||||||
|
} else {
|
||||||
|
index := NewIndex(indexName, IndexType)
|
||||||
|
index.AddColumn(col.Name)
|
||||||
|
table.AddIndex(index)
|
||||||
|
col.Indexes[index.Name] = true
|
||||||
|
}
|
||||||
|
} else if indexType == UniqueType {
|
||||||
|
if indexName == "" {
|
||||||
|
indexName = col.Name
|
||||||
|
}
|
||||||
|
if index, ok := table.Indexes[indexName]; ok {
|
||||||
|
index.AddColumn(col.Name)
|
||||||
|
col.Indexes[index.Name] = true
|
||||||
|
} else {
|
||||||
|
index := NewIndex(indexName, UniqueType)
|
||||||
|
index.AddColumn(col.Name)
|
||||||
|
table.AddIndex(index)
|
||||||
|
col.Indexes[index.Name] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sqlType := Type2SQLType(fieldType)
|
sqlType := Type2SQLType(fieldType)
|
||||||
col = &Column{engine.Mapper.Obj2Table(t.Field(i).Name), t.Field(i).Name, sqlType,
|
col = &Column{engine.Mapper.Obj2Table(t.Field(i).Name), t.Field(i).Name, sqlType,
|
||||||
sqlType.DefaultLength, sqlType.DefaultLength2, true, "", nil, false, false,
|
sqlType.DefaultLength, sqlType.DefaultLength2, true, "", make(map[string]bool), false, false,
|
||||||
TWOSIDES, false, false, ""}
|
TWOSIDES, false, false, false}
|
||||||
}
|
}
|
||||||
if col.IsAutoIncrement {
|
if col.IsAutoIncrement {
|
||||||
col.Nullable = false
|
col.Nullable = false
|
||||||
|
@ -498,6 +541,20 @@ func (engine *Engine) IsTableExist(bean interface{}) (bool, error) {
|
||||||
return has, err
|
return has, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// create indexes
|
||||||
|
func (engine *Engine) CreateIndexes(bean interface{}) error {
|
||||||
|
session := engine.NewSession()
|
||||||
|
defer session.Close()
|
||||||
|
return session.CreateIndexes(bean)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create uniques
|
||||||
|
func (engine *Engine) CreateUniques(bean interface{}) error {
|
||||||
|
session := engine.NewSession()
|
||||||
|
defer session.Close()
|
||||||
|
return session.CreateUniques(bean)
|
||||||
|
}
|
||||||
|
|
||||||
// If enabled cache, clear the cache bean
|
// If enabled cache, clear the cache bean
|
||||||
func (engine *Engine) ClearCacheBean(bean interface{}, id int64) error {
|
func (engine *Engine) ClearCacheBean(bean interface{}, id int64) error {
|
||||||
t := rType(bean)
|
t := rType(bean)
|
||||||
|
@ -585,7 +642,7 @@ func (engine *Engine) Sync(beans ...interface{}) error {
|
||||||
session := engine.NewSession()
|
session := engine.NewSession()
|
||||||
session.Statement.RefTable = table
|
session.Statement.RefTable = table
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
if index.IsUnique {
|
if index.Type == UniqueType {
|
||||||
isExist, err := session.isIndexExist(table.Name, name, true)
|
isExist, err := session.isIndexExist(table.Name, name, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -599,7 +656,7 @@ func (engine *Engine) Sync(beans ...interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if index.Type == IndexType {
|
||||||
isExist, err := session.isIndexExist(table.Name, name, false)
|
isExist, err := session.isIndexExist(table.Name, name, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -613,6 +670,8 @@ func (engine *Engine) Sync(beans ...interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return errors.New("unknow index type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
error.go
13
error.go
|
@ -5,10 +5,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrParamsType error = errors.New("params type error")
|
ErrParamsType error = errors.New("Params type error")
|
||||||
ErrTableNotFound error = errors.New("not found table")
|
ErrTableNotFound error = errors.New("Not found table")
|
||||||
ErrUnSupportedType error = errors.New("unsupported type error")
|
ErrUnSupportedType error = errors.New("Unsupported type error")
|
||||||
ErrNotExist error = errors.New("not exist error")
|
ErrNotExist error = errors.New("Not exist error")
|
||||||
ErrCacheFailed error = errors.New("cache failed")
|
ErrCacheFailed error = errors.New("Cache failed")
|
||||||
ErrNeedDeletedCond error = errors.New("delete need at least one condition")
|
ErrNeedDeletedCond error = errors.New("Delete need at least one condition")
|
||||||
|
ErrNotImplemented error = errors.New("Not implemented.")
|
||||||
)
|
)
|
||||||
|
|
|
@ -9,9 +9,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type SyncUser struct {
|
type SyncUser struct {
|
||||||
Id int64
|
Id int64
|
||||||
Name string `xorm:"unique"`
|
Name string `xorm:"unique"`
|
||||||
Age int `xorm:"index"`
|
Age int `xorm:"index"`
|
||||||
|
Title string
|
||||||
|
Address string
|
||||||
|
Genre string
|
||||||
|
Area string
|
||||||
|
Date int
|
||||||
}
|
}
|
||||||
|
|
||||||
type SyncLoginInfo struct {
|
type SyncLoginInfo struct {
|
||||||
|
@ -61,5 +66,19 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
user := &SyncUser{
|
||||||
|
Name: "testsdf",
|
||||||
|
Age: 15,
|
||||||
|
Title: "newsfds",
|
||||||
|
Address: "fasfdsafdsaf",
|
||||||
|
Genre: "fsafd",
|
||||||
|
Area: "fafdsafd",
|
||||||
|
Date: 1000,
|
||||||
|
}
|
||||||
|
_, err = Orm.Insert(user)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,9 @@ func titleCasedName(name string) string {
|
||||||
switch {
|
switch {
|
||||||
case upNextChar:
|
case upNextChar:
|
||||||
upNextChar = false
|
upNextChar = false
|
||||||
chr -= ('a' - 'A')
|
if 'a' <= chr && chr <= 'z' {
|
||||||
|
chr -= ('a' - 'A')
|
||||||
|
}
|
||||||
case chr == '_':
|
case chr == '_':
|
||||||
upNextChar = true
|
upNextChar = true
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -17,7 +17,8 @@ type mymysql struct {
|
||||||
passwd string
|
passwd string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mymysql) Init(uri string) error {
|
func (db *mymysql) Init(drivername, uri string) error {
|
||||||
|
db.mysql.base.init(drivername, uri)
|
||||||
pd := strings.SplitN(uri, "*", 2)
|
pd := strings.SplitN(uri, "*", 2)
|
||||||
if len(pd) == 2 {
|
if len(pd) == 2 {
|
||||||
// Parse protocol part of URI
|
// Parse protocol part of URI
|
||||||
|
|
169
mysql.go
169
mysql.go
|
@ -2,14 +2,26 @@ package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
//"fmt"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
//"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type base struct {
|
||||||
|
drivername string
|
||||||
|
dataSourceName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *base) init(drivername, dataSourceName string) {
|
||||||
|
b.drivername, b.dataSourceName = drivername, dataSourceName
|
||||||
|
}
|
||||||
|
|
||||||
type mysql struct {
|
type mysql struct {
|
||||||
|
base
|
||||||
user string
|
user string
|
||||||
passwd string
|
passwd string
|
||||||
net string
|
net string
|
||||||
|
@ -56,7 +68,8 @@ func (cfg *mysql) parseDSN(dsn string) (err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *mysql) Init(uri string) error {
|
func (db *mysql) Init(drivername, uri string) error {
|
||||||
|
db.base.init(drivername, uri)
|
||||||
return db.parseDSN(uri)
|
return db.parseDSN(uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,3 +146,153 @@ func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) {
|
||||||
sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?"
|
sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?"
|
||||||
return sql, args
|
return sql, args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *mysql) GetColumns(tableName string) (map[string]*Column, error) {
|
||||||
|
args := []interface{}{db.dbname, tableName}
|
||||||
|
s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," +
|
||||||
|
" `COLUMN_KEY`, `EXTRA` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
|
||||||
|
cnn, err := sql.Open(db.drivername, db.dataSourceName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cnn.Close()
|
||||||
|
res, err := query(cnn, s, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cols := make(map[string]*Column)
|
||||||
|
for _, record := range res {
|
||||||
|
col := new(Column)
|
||||||
|
col.Indexes = make(map[string]bool)
|
||||||
|
for name, content := range record {
|
||||||
|
switch name {
|
||||||
|
case "COLUMN_NAME":
|
||||||
|
col.Name = strings.Trim(string(content), "` ")
|
||||||
|
case "IS_NULLABLE":
|
||||||
|
if "YES" == string(content) {
|
||||||
|
col.Nullable = true
|
||||||
|
}
|
||||||
|
case "COLUMN_DEFAULT":
|
||||||
|
// add ''
|
||||||
|
col.Default = string(content)
|
||||||
|
case "COLUMN_TYPE":
|
||||||
|
cts := strings.Split(string(content), "(")
|
||||||
|
var len1, len2 int
|
||||||
|
if len(cts) == 2 {
|
||||||
|
lens := strings.Split(cts[1][0:len(cts[1])-1], ",")
|
||||||
|
len1, err = strconv.Atoi(strings.TrimSpace(lens[0]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(lens) == 2 {
|
||||||
|
len2, err = strconv.Atoi(lens[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
colName := cts[0]
|
||||||
|
colType := strings.ToUpper(colName)
|
||||||
|
col.Length = len1
|
||||||
|
col.Length2 = len2
|
||||||
|
if _, ok := sqlTypes[colType]; ok {
|
||||||
|
col.SQLType = SQLType{colType, len1, len2}
|
||||||
|
} else {
|
||||||
|
return nil, errors.New(fmt.Sprintf("unkonw colType %v", colType))
|
||||||
|
}
|
||||||
|
case "COLUMN_KEY":
|
||||||
|
key := string(content)
|
||||||
|
if key == "PRI" {
|
||||||
|
col.IsPrimaryKey = true
|
||||||
|
}
|
||||||
|
if key == "UNI" {
|
||||||
|
//col.is
|
||||||
|
}
|
||||||
|
case "EXTRA":
|
||||||
|
extra := string(content)
|
||||||
|
if extra == "auto_increment" {
|
||||||
|
col.IsAutoIncrement = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cols[col.Name] = col
|
||||||
|
}
|
||||||
|
return cols, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *mysql) GetTables() ([]*Table, error) {
|
||||||
|
args := []interface{}{db.dbname}
|
||||||
|
s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=?"
|
||||||
|
cnn, err := sql.Open(db.drivername, db.dataSourceName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cnn.Close()
|
||||||
|
res, err := query(cnn, s, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tables := make([]*Table, 0)
|
||||||
|
for _, record := range res {
|
||||||
|
table := new(Table)
|
||||||
|
for name, content := range record {
|
||||||
|
switch name {
|
||||||
|
case "TABLE_NAME":
|
||||||
|
table.Name = strings.Trim(string(content), "` ")
|
||||||
|
case "ENGINE":
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tables = append(tables, table)
|
||||||
|
}
|
||||||
|
return tables, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *mysql) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
|
args := []interface{}{db.dbname, tableName}
|
||||||
|
s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?"
|
||||||
|
cnn, err := sql.Open(db.drivername, db.dataSourceName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cnn.Close()
|
||||||
|
res, err := query(cnn, s, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
indexes := make(map[string]*Index, 0)
|
||||||
|
for _, record := range res {
|
||||||
|
var indexType int
|
||||||
|
var indexName, colName string
|
||||||
|
for name, content := range record {
|
||||||
|
switch name {
|
||||||
|
case "NON_UNIQUE":
|
||||||
|
if "YES" == string(content) {
|
||||||
|
indexType = IndexType
|
||||||
|
} else {
|
||||||
|
indexType = UniqueType
|
||||||
|
}
|
||||||
|
case "INDEX_NAME":
|
||||||
|
indexName = string(content)
|
||||||
|
case "COLUMN_NAME":
|
||||||
|
colName = strings.Trim(string(content), "` ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if indexName == "PRIMARY" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
indexName = indexName[5+len(tableName) : len(indexName)]
|
||||||
|
|
||||||
|
var index *Index
|
||||||
|
var ok bool
|
||||||
|
if index, ok = indexes[indexName]; !ok {
|
||||||
|
index = new(Index)
|
||||||
|
index.Type = indexType
|
||||||
|
index.Name = indexName
|
||||||
|
indexes[indexName] = index
|
||||||
|
}
|
||||||
|
index.AddColumn(colName)
|
||||||
|
}
|
||||||
|
return indexes, nil
|
||||||
|
}
|
||||||
|
|
149
postgres.go
149
postgres.go
|
@ -1,6 +1,7 @@
|
||||||
package xorm
|
package xorm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -8,6 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type postgres struct {
|
type postgres struct {
|
||||||
|
base
|
||||||
dbname string
|
dbname string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +46,9 @@ func parseOpts(name string, o values) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *postgres) Init(uri string) error {
|
func (db *postgres) Init(drivername, uri string) error {
|
||||||
|
db.base.init(drivername, uri)
|
||||||
|
|
||||||
o := make(values)
|
o := make(values)
|
||||||
parseOpts(uri, o)
|
parseOpts(uri, o)
|
||||||
|
|
||||||
|
@ -135,3 +139,146 @@ func (db *postgres) ColumnCheckSql(tableName, colName string) (string, []interfa
|
||||||
return "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = ?" +
|
return "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = ?" +
|
||||||
" AND column_name = ?", args
|
" AND column_name = ?", args
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *postgres) GetColumns(tableName string) (map[string]*Column, error) {
|
||||||
|
args := []interface{}{tableName}
|
||||||
|
s := "SELECT column_name, column_default, is_nullable, data_type, character_maximum_length" +
|
||||||
|
", numeric_precision, numeric_precision_radix FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1"
|
||||||
|
|
||||||
|
cnn, err := sql.Open(db.drivername, db.dataSourceName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cnn.Close()
|
||||||
|
res, err := query(cnn, s, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
cols := make(map[string]*Column)
|
||||||
|
for _, record := range res {
|
||||||
|
col := new(Column)
|
||||||
|
col.Indexes = make(map[string]bool)
|
||||||
|
for name, content := range record {
|
||||||
|
switch name {
|
||||||
|
case "column_name":
|
||||||
|
col.Name = strings.Trim(string(content), `" `)
|
||||||
|
case "column_default":
|
||||||
|
if strings.HasPrefix(string(content), "nextval") {
|
||||||
|
col.IsPrimaryKey = true
|
||||||
|
}
|
||||||
|
case "is_nullable":
|
||||||
|
if string(content) == "YES" {
|
||||||
|
col.Nullable = true
|
||||||
|
} else {
|
||||||
|
col.Nullable = false
|
||||||
|
}
|
||||||
|
case "data_type":
|
||||||
|
ct := string(content)
|
||||||
|
switch ct {
|
||||||
|
case "character varying", "character":
|
||||||
|
col.SQLType = SQLType{Varchar, 0, 0}
|
||||||
|
case "timestamp without time zone":
|
||||||
|
col.SQLType = SQLType{DateTime, 0, 0}
|
||||||
|
case "double precision":
|
||||||
|
col.SQLType = SQLType{Double, 0, 0}
|
||||||
|
case "boolean":
|
||||||
|
col.SQLType = SQLType{Bool, 0, 0}
|
||||||
|
case "time without time zone":
|
||||||
|
col.SQLType = SQLType{Time, 0, 0}
|
||||||
|
default:
|
||||||
|
col.SQLType = SQLType{strings.ToUpper(ct), 0, 0}
|
||||||
|
}
|
||||||
|
if _, ok := sqlTypes[col.SQLType.Name]; !ok {
|
||||||
|
return nil, errors.New(fmt.Sprintf("unkonw colType %v", ct))
|
||||||
|
}
|
||||||
|
case "character_maximum_length":
|
||||||
|
i, err := strconv.Atoi(string(content))
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.New("retrieve length error")
|
||||||
|
}
|
||||||
|
col.Length = i
|
||||||
|
case "numeric_precision":
|
||||||
|
case "numeric_precision_radix":
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cols[col.Name] = col
|
||||||
|
}
|
||||||
|
|
||||||
|
return cols, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *postgres) GetTables() ([]*Table, error) {
|
||||||
|
args := []interface{}{}
|
||||||
|
s := "SELECT tablename FROM pg_tables where schemaname = 'public'"
|
||||||
|
cnn, err := sql.Open(db.drivername, db.dataSourceName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cnn.Close()
|
||||||
|
res, err := query(cnn, s, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tables := make([]*Table, 0)
|
||||||
|
for _, record := range res {
|
||||||
|
table := new(Table)
|
||||||
|
for name, content := range record {
|
||||||
|
switch name {
|
||||||
|
case "tablename":
|
||||||
|
table.Name = string(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tables = append(tables, table)
|
||||||
|
}
|
||||||
|
return tables, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *postgres) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
|
args := []interface{}{tableName}
|
||||||
|
s := "SELECT tablename, indexname, indexdef FROM pg_indexes WHERE schemaname = 'public' and tablename = $1"
|
||||||
|
|
||||||
|
cnn, err := sql.Open(db.drivername, db.dataSourceName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cnn.Close()
|
||||||
|
res, err := query(cnn, s, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
indexes := make(map[string]*Index, 0)
|
||||||
|
for _, record := range res {
|
||||||
|
var indexType int
|
||||||
|
var indexName string
|
||||||
|
var colNames []string
|
||||||
|
|
||||||
|
for name, content := range record {
|
||||||
|
switch name {
|
||||||
|
case "indexname":
|
||||||
|
indexName = strings.Trim(string(content), `" `)
|
||||||
|
case "indexdef":
|
||||||
|
c := string(content)
|
||||||
|
if strings.HasPrefix(c, "CREATE UNIQUE INDEX") {
|
||||||
|
indexType = UniqueType
|
||||||
|
} else {
|
||||||
|
indexType = IndexType
|
||||||
|
}
|
||||||
|
cs := strings.Split(c, "(")
|
||||||
|
colNames = strings.Split(cs[1][0:len(cs[1])-1], ",")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(indexName, "_pkey") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
indexName = indexName[5+len(tableName) : len(indexName)]
|
||||||
|
|
||||||
|
index := &Index{Name: indexName, Type: indexType, Cols: make([]string, 0)}
|
||||||
|
for _, colName := range colNames {
|
||||||
|
index.Cols = append(index.Cols, strings.Trim(colName, `" `))
|
||||||
|
}
|
||||||
|
indexes[index.Name] = index
|
||||||
|
}
|
||||||
|
return indexes, nil
|
||||||
|
}
|
||||||
|
|
124
session.go
124
session.go
|
@ -11,6 +11,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Struct Session keep a pointer to sql.DB and provides all execution of all
|
||||||
|
// kind of database operations.
|
||||||
type Session struct {
|
type Session struct {
|
||||||
Db *sql.DB
|
Db *sql.DB
|
||||||
Engine *Engine
|
Engine *Engine
|
||||||
|
@ -22,6 +24,7 @@ type Session struct {
|
||||||
IsAutoClose bool
|
IsAutoClose bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Init reset the session as the init status.
|
||||||
func (session *Session) Init() {
|
func (session *Session) Init() {
|
||||||
session.Statement = Statement{Engine: session.Engine}
|
session.Statement = Statement{Engine: session.Engine}
|
||||||
session.Statement.Init()
|
session.Statement.Init()
|
||||||
|
@ -30,6 +33,7 @@ func (session *Session) Init() {
|
||||||
session.IsAutoClose = false
|
session.IsAutoClose = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Close release the connection from pool
|
||||||
func (session *Session) Close() {
|
func (session *Session) Close() {
|
||||||
defer func() {
|
defer func() {
|
||||||
if session.Db != nil {
|
if session.Db != nil {
|
||||||
|
@ -41,56 +45,64 @@ func (session *Session) Close() {
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Sql provides raw sql input parameter. When you have a complex SQL statement
|
||||||
|
// and cannot use Where, Id, In and etc. Methods to describe, you can use Sql.
|
||||||
func (session *Session) Sql(querystring string, args ...interface{}) *Session {
|
func (session *Session) Sql(querystring string, args ...interface{}) *Session {
|
||||||
session.Statement.Sql(querystring, args...)
|
session.Statement.Sql(querystring, args...)
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Where provides custom query condition.
|
||||||
func (session *Session) Where(querystring string, args ...interface{}) *Session {
|
func (session *Session) Where(querystring string, args ...interface{}) *Session {
|
||||||
session.Statement.Where(querystring, args...)
|
session.Statement.Where(querystring, args...)
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Id provides converting id as a query condition
|
||||||
func (session *Session) Id(id int64) *Session {
|
func (session *Session) Id(id int64) *Session {
|
||||||
session.Statement.Id(id)
|
session.Statement.Id(id)
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Table can input a string or pointer to struct for special a table to operate.
|
||||||
func (session *Session) Table(tableNameOrBean interface{}) *Session {
|
func (session *Session) Table(tableNameOrBean interface{}) *Session {
|
||||||
session.Statement.Table(tableNameOrBean)
|
session.Statement.Table(tableNameOrBean)
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method In provides a query string like "id in (1, 2, 3)"
|
||||||
func (session *Session) In(column string, args ...interface{}) *Session {
|
func (session *Session) In(column string, args ...interface{}) *Session {
|
||||||
session.Statement.In(column, args...)
|
session.Statement.In(column, args...)
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Cols provides some columns to special
|
||||||
func (session *Session) Cols(columns ...string) *Session {
|
func (session *Session) Cols(columns ...string) *Session {
|
||||||
session.Statement.Cols(columns...)
|
session.Statement.Cols(columns...)
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method NoAutoTime means do not automatically give created field and updated field
|
||||||
|
// the current time on the current session temporarily
|
||||||
func (session *Session) NoAutoTime() *Session {
|
func (session *Session) NoAutoTime() *Session {
|
||||||
session.Statement.UseAutoTime = false
|
session.Statement.UseAutoTime = false
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
/*func (session *Session) Trans(t string) *Session {
|
// Method Limit provide limit and offset query condition
|
||||||
session.TransType = t
|
|
||||||
return session
|
|
||||||
}*/
|
|
||||||
|
|
||||||
func (session *Session) Limit(limit int, start ...int) *Session {
|
func (session *Session) Limit(limit int, start ...int) *Session {
|
||||||
session.Statement.Limit(limit, start...)
|
session.Statement.Limit(limit, start...)
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method OrderBy provide order by query condition, the input parameter is the content
|
||||||
|
// after order by on a sql statement.
|
||||||
func (session *Session) OrderBy(order string) *Session {
|
func (session *Session) OrderBy(order string) *Session {
|
||||||
session.Statement.OrderBy(order)
|
session.Statement.OrderBy(order)
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Desc provide desc order by query condition, the input parameters are columns.
|
||||||
func (session *Session) Desc(colNames ...string) *Session {
|
func (session *Session) Desc(colNames ...string) *Session {
|
||||||
if session.Statement.OrderStr != "" {
|
if session.Statement.OrderStr != "" {
|
||||||
session.Statement.OrderStr += ", "
|
session.Statement.OrderStr += ", "
|
||||||
|
@ -101,6 +113,7 @@ func (session *Session) Desc(colNames ...string) *Session {
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Asc provide asc order by query condition, the input parameters are columns.
|
||||||
func (session *Session) Asc(colNames ...string) *Session {
|
func (session *Session) Asc(colNames ...string) *Session {
|
||||||
if session.Statement.OrderStr != "" {
|
if session.Statement.OrderStr != "" {
|
||||||
session.Statement.OrderStr += ", "
|
session.Statement.OrderStr += ", "
|
||||||
|
@ -111,16 +124,19 @@ func (session *Session) Asc(colNames ...string) *Session {
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method StoreEngine is only avialble mysql dialect currently
|
||||||
func (session *Session) StoreEngine(storeEngine string) *Session {
|
func (session *Session) StoreEngine(storeEngine string) *Session {
|
||||||
session.Statement.StoreEngine = storeEngine
|
session.Statement.StoreEngine = storeEngine
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method StoreEngine is only avialble charset dialect currently
|
||||||
func (session *Session) Charset(charset string) *Session {
|
func (session *Session) Charset(charset string) *Session {
|
||||||
session.Statement.Charset = charset
|
session.Statement.Charset = charset
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method Cascade
|
||||||
func (session *Session) Cascade(trueOrFalse ...bool) *Session {
|
func (session *Session) Cascade(trueOrFalse ...bool) *Session {
|
||||||
if len(trueOrFalse) >= 1 {
|
if len(trueOrFalse) >= 1 {
|
||||||
session.Statement.UseCascade = trueOrFalse[0]
|
session.Statement.UseCascade = trueOrFalse[0]
|
||||||
|
@ -128,6 +144,8 @@ func (session *Session) Cascade(trueOrFalse ...bool) *Session {
|
||||||
return session
|
return session
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method NoCache ask this session do not retrieve data from cache system and
|
||||||
|
// get data from database directly.
|
||||||
func (session *Session) NoCache() *Session {
|
func (session *Session) NoCache() *Session {
|
||||||
session.Statement.UseCache = false
|
session.Statement.UseCache = false
|
||||||
return session
|
return session
|
||||||
|
@ -841,7 +859,7 @@ func (session *Session) isColumnExist(tableName, colName string) (bool, error) {
|
||||||
if session.IsAutoClose {
|
if session.IsAutoClose {
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
}
|
}
|
||||||
sql, args := session.Engine.Dialect.ColumnCheckSql(tableName, colName)
|
sql, args := session.Engine.dialect.ColumnCheckSql(tableName, colName)
|
||||||
results, err := session.query(sql, args...)
|
results, err := session.query(sql, args...)
|
||||||
return len(results) > 0, err
|
return len(results) > 0, err
|
||||||
}
|
}
|
||||||
|
@ -855,7 +873,7 @@ func (session *Session) isTableExist(tableName string) (bool, error) {
|
||||||
if session.IsAutoClose {
|
if session.IsAutoClose {
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
}
|
}
|
||||||
sql, args := session.Engine.Dialect.TableCheckSql(tableName)
|
sql, args := session.Engine.dialect.TableCheckSql(tableName)
|
||||||
results, err := session.query(sql, args...)
|
results, err := session.query(sql, args...)
|
||||||
return len(results) > 0, err
|
return len(results) > 0, err
|
||||||
}
|
}
|
||||||
|
@ -875,7 +893,7 @@ func (session *Session) isIndexExist(tableName, idxName string, unique bool) (bo
|
||||||
} else {
|
} else {
|
||||||
idx = indexName(tableName, idxName)
|
idx = indexName(tableName, idxName)
|
||||||
}
|
}
|
||||||
sql, args := session.Engine.Dialect.IndexCheckSql(tableName, idx)
|
sql, args := session.Engine.dialect.IndexCheckSql(tableName, idx)
|
||||||
results, err := session.query(sql, args...)
|
results, err := session.query(sql, args...)
|
||||||
return len(results) > 0, err
|
return len(results) > 0, err
|
||||||
}
|
}
|
||||||
|
@ -906,7 +924,7 @@ func (session *Session) addIndex(tableName, idxName string) error {
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
}
|
}
|
||||||
//fmt.Println(idxName)
|
//fmt.Println(idxName)
|
||||||
cols := session.Statement.RefTable.Indexes[idxName].GenColsStr()
|
cols := session.Statement.RefTable.Indexes[idxName].Cols
|
||||||
sql, args := session.Statement.genAddIndexStr(indexName(tableName, idxName), cols)
|
sql, args := session.Statement.genAddIndexStr(indexName(tableName, idxName), cols)
|
||||||
_, err = session.exec(sql, args...)
|
_, err = session.exec(sql, args...)
|
||||||
return err
|
return err
|
||||||
|
@ -922,7 +940,7 @@ func (session *Session) addUnique(tableName, uqeName string) error {
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
}
|
}
|
||||||
//fmt.Println(uqeName, session.Statement.RefTable.Uniques)
|
//fmt.Println(uqeName, session.Statement.RefTable.Uniques)
|
||||||
cols := session.Statement.RefTable.Indexes[uqeName].GenColsStr()
|
cols := session.Statement.RefTable.Indexes[uqeName].Cols
|
||||||
sql, args := session.Statement.genAddUniqueStr(uniqueName(tableName, uqeName), cols)
|
sql, args := session.Statement.genAddUniqueStr(uniqueName(tableName, uqeName), cols)
|
||||||
_, err = session.exec(sql, args...)
|
_, err = session.exec(sql, args...)
|
||||||
return err
|
return err
|
||||||
|
@ -950,6 +968,79 @@ func (session *Session) DropAll() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func query(db *sql.DB, sql string, params ...interface{}) (resultsSlice []map[string][]byte, err error) {
|
||||||
|
s, err := db.Prepare(sql)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer s.Close()
|
||||||
|
res, err := s.Query(params...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer res.Close()
|
||||||
|
fields, err := res.Columns()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for res.Next() {
|
||||||
|
result := make(map[string][]byte)
|
||||||
|
var scanResultContainers []interface{}
|
||||||
|
for i := 0; i < len(fields); i++ {
|
||||||
|
var scanResultContainer interface{}
|
||||||
|
scanResultContainers = append(scanResultContainers, &scanResultContainer)
|
||||||
|
}
|
||||||
|
if err := res.Scan(scanResultContainers...); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for ii, key := range fields {
|
||||||
|
rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii]))
|
||||||
|
|
||||||
|
//if row is null then ignore
|
||||||
|
if rawValue.Interface() == nil {
|
||||||
|
//fmt.Println("ignore ...", key, rawValue)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
aa := reflect.TypeOf(rawValue.Interface())
|
||||||
|
vv := reflect.ValueOf(rawValue.Interface())
|
||||||
|
var str string
|
||||||
|
switch aa.Kind() {
|
||||||
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
str = strconv.FormatInt(vv.Int(), 10)
|
||||||
|
result[key] = []byte(str)
|
||||||
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
str = strconv.FormatUint(vv.Uint(), 10)
|
||||||
|
result[key] = []byte(str)
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
str = strconv.FormatFloat(vv.Float(), 'f', -1, 64)
|
||||||
|
result[key] = []byte(str)
|
||||||
|
case reflect.Slice:
|
||||||
|
switch aa.Elem().Kind() {
|
||||||
|
case reflect.Uint8:
|
||||||
|
result[key] = rawValue.Interface().([]byte)
|
||||||
|
default:
|
||||||
|
//session.Engine.LogError("Unsupported type")
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
str = vv.String()
|
||||||
|
result[key] = []byte(str)
|
||||||
|
//时间类型
|
||||||
|
case reflect.Struct:
|
||||||
|
if aa.String() == "time.Time" {
|
||||||
|
str = rawValue.Interface().(time.Time).Format("2006-01-02 15:04:05.000 -0700")
|
||||||
|
result[key] = []byte(str)
|
||||||
|
} else {
|
||||||
|
//session.Engine.LogError("Unsupported struct type")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
//session.Engine.LogError("Unsupported type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resultsSlice = append(resultsSlice, result)
|
||||||
|
}
|
||||||
|
return resultsSlice, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (session *Session) query(sql string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
|
func (session *Session) query(sql string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
|
||||||
for _, filter := range session.Engine.Filters {
|
for _, filter := range session.Engine.Filters {
|
||||||
sql = filter.Do(sql, session)
|
sql = filter.Do(sql, session)
|
||||||
|
@ -958,7 +1049,9 @@ func (session *Session) query(sql string, paramStr ...interface{}) (resultsSlice
|
||||||
session.Engine.LogSQL(sql)
|
session.Engine.LogSQL(sql)
|
||||||
session.Engine.LogSQL(paramStr)
|
session.Engine.LogSQL(paramStr)
|
||||||
|
|
||||||
s, err := session.Db.Prepare(sql)
|
return query(session.Db, sql, paramStr...)
|
||||||
|
|
||||||
|
/*s, err := session.Db.Prepare(sql)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1027,7 +1120,7 @@ func (session *Session) query(sql string, paramStr ...interface{}) (resultsSlice
|
||||||
}
|
}
|
||||||
resultsSlice = append(resultsSlice, result)
|
resultsSlice = append(resultsSlice, result)
|
||||||
}
|
}
|
||||||
return resultsSlice, nil
|
return resultsSlice, nil*/
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *Session) Query(sql string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
|
func (session *Session) Query(sql string, paramStr ...interface{}) (resultsSlice []map[string][]byte, err error) {
|
||||||
|
@ -1451,9 +1544,9 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||||
|
|
||||||
var v interface{} = id
|
var v interface{} = id
|
||||||
switch pkValue.Type().Kind() {
|
switch pkValue.Type().Kind() {
|
||||||
case reflect.Int8, reflect.Int16, reflect.Int32:
|
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int:
|
||||||
v = int(id)
|
v = int(id)
|
||||||
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
||||||
v = uint(id)
|
v = uint(id)
|
||||||
}
|
}
|
||||||
pkValue.Set(reflect.ValueOf(v))
|
pkValue.Set(reflect.ValueOf(v))
|
||||||
|
@ -1461,6 +1554,9 @@ func (session *Session) innerInsert(bean interface{}) (int64, error) {
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method InsertOne insert only one struct into database as a record.
|
||||||
|
// The in parameter bean must a struct or a point to struct. The return
|
||||||
|
// parameter is lastInsertId and error
|
||||||
func (session *Session) InsertOne(bean interface{}) (int64, error) {
|
func (session *Session) InsertOne(bean interface{}) (int64, error) {
|
||||||
err := session.newDb()
|
err := session.newDb()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
148
sqlite3.go
148
sqlite3.go
|
@ -1,9 +1,17 @@
|
||||||
package xorm
|
package xorm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type sqlite3 struct {
|
type sqlite3 struct {
|
||||||
|
base
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *sqlite3) Init(uri string) error {
|
func (db *sqlite3) Init(drivername, dataSourceName string) error {
|
||||||
|
db.base.init(drivername, dataSourceName)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,5 +75,141 @@ func (db *sqlite3) TableCheckSql(tableName string) (string, []interface{}) {
|
||||||
|
|
||||||
func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
|
func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interface{}) {
|
||||||
args := []interface{}{tableName}
|
args := []interface{}{tableName}
|
||||||
return "SELECT name FROM sqlite_master WHERE type='table' and name = ? and sql like '%`" + colName + "`%'", args
|
fmt.Println(tableName, colName)
|
||||||
|
sql := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))"
|
||||||
|
fmt.Println(sql)
|
||||||
|
return sql, args
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *sqlite3) GetColumns(tableName string) (map[string]*Column, error) {
|
||||||
|
args := []interface{}{tableName}
|
||||||
|
s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?"
|
||||||
|
cnn, err := sql.Open(db.drivername, db.dataSourceName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cnn.Close()
|
||||||
|
res, err := query(cnn, s, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var sql string
|
||||||
|
for _, record := range res {
|
||||||
|
for name, content := range record {
|
||||||
|
if name == "sql" {
|
||||||
|
sql = string(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nStart := strings.Index(sql, "(")
|
||||||
|
nEnd := strings.Index(sql, ")")
|
||||||
|
colCreates := strings.Split(sql[nStart+1:nEnd], ",")
|
||||||
|
cols := make(map[string]*Column)
|
||||||
|
for _, colStr := range colCreates {
|
||||||
|
fields := strings.Fields(strings.TrimSpace(colStr))
|
||||||
|
col := new(Column)
|
||||||
|
col.Indexes = make(map[string]bool)
|
||||||
|
for idx, field := range fields {
|
||||||
|
if idx == 0 {
|
||||||
|
col.Name = strings.Trim(field, "`[] ")
|
||||||
|
continue
|
||||||
|
} else if idx == 1 {
|
||||||
|
col.SQLType = SQLType{field, 0, 0}
|
||||||
|
}
|
||||||
|
switch field {
|
||||||
|
case "PRIMARY":
|
||||||
|
col.IsPrimaryKey = true
|
||||||
|
case "AUTOINCREMENT":
|
||||||
|
col.IsAutoIncrement = true
|
||||||
|
case "NULL":
|
||||||
|
if fields[idx-1] == "NOT" {
|
||||||
|
col.Nullable = false
|
||||||
|
} else {
|
||||||
|
col.Nullable = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cols[col.Name] = col
|
||||||
|
}
|
||||||
|
return cols, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *sqlite3) GetTables() ([]*Table, error) {
|
||||||
|
args := []interface{}{}
|
||||||
|
s := "SELECT name FROM sqlite_master WHERE type='table'"
|
||||||
|
|
||||||
|
cnn, err := sql.Open(db.drivername, db.dataSourceName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cnn.Close()
|
||||||
|
res, err := query(cnn, s, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tables := make([]*Table, 0)
|
||||||
|
for _, record := range res {
|
||||||
|
table := new(Table)
|
||||||
|
for name, content := range record {
|
||||||
|
switch name {
|
||||||
|
case "name":
|
||||||
|
table.Name = string(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if table.Name == "sqlite_sequence" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tables = append(tables, table)
|
||||||
|
}
|
||||||
|
return tables, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *sqlite3) GetIndexes(tableName string) (map[string]*Index, error) {
|
||||||
|
args := []interface{}{tableName}
|
||||||
|
s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?"
|
||||||
|
cnn, err := sql.Open(db.drivername, db.dataSourceName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer cnn.Close()
|
||||||
|
res, err := query(cnn, s, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
indexes := make(map[string]*Index, 0)
|
||||||
|
for _, record := range res {
|
||||||
|
var sql string
|
||||||
|
index := new(Index)
|
||||||
|
for name, content := range record {
|
||||||
|
if name == "sql" {
|
||||||
|
sql = string(content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nNStart := strings.Index(sql, "INDEX")
|
||||||
|
nNEnd := strings.Index(sql, "ON")
|
||||||
|
indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []")
|
||||||
|
index.Name = indexName[5+len(tableName) : len(indexName)]
|
||||||
|
|
||||||
|
if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") {
|
||||||
|
index.Type = UniqueType
|
||||||
|
} else {
|
||||||
|
index.Type = IndexType
|
||||||
|
}
|
||||||
|
|
||||||
|
nStart := strings.Index(sql, "(")
|
||||||
|
nEnd := strings.Index(sql, ")")
|
||||||
|
colIndexes := strings.Split(sql[nStart+1:nEnd], ",")
|
||||||
|
|
||||||
|
index.Cols = make([]string, 0)
|
||||||
|
for _, col := range colIndexes {
|
||||||
|
index.Cols = append(index.Cols, strings.Trim(col, "` []"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return indexes, nil
|
||||||
}
|
}
|
||||||
|
|
30
statement.go
30
statement.go
|
@ -262,15 +262,15 @@ func (statement *Statement) genCreateSQL() string {
|
||||||
sql := "CREATE TABLE IF NOT EXISTS " + statement.Engine.Quote(statement.TableName()) + " ("
|
sql := "CREATE TABLE IF NOT EXISTS " + statement.Engine.Quote(statement.TableName()) + " ("
|
||||||
for _, colName := range statement.RefTable.ColumnsSeq {
|
for _, colName := range statement.RefTable.ColumnsSeq {
|
||||||
col := statement.RefTable.Columns[colName]
|
col := statement.RefTable.Columns[colName]
|
||||||
sql += col.String(statement.Engine)
|
sql += col.String(statement.Engine.dialect)
|
||||||
sql = strings.TrimSpace(sql)
|
sql = strings.TrimSpace(sql)
|
||||||
sql += ", "
|
sql += ", "
|
||||||
}
|
}
|
||||||
sql = sql[:len(sql)-2] + ")"
|
sql = sql[:len(sql)-2] + ")"
|
||||||
if statement.Engine.Dialect.SupportEngine() && statement.StoreEngine != "" {
|
if statement.Engine.dialect.SupportEngine() && statement.StoreEngine != "" {
|
||||||
sql += " ENGINE=" + statement.StoreEngine
|
sql += " ENGINE=" + statement.StoreEngine
|
||||||
}
|
}
|
||||||
if statement.Engine.Dialect.SupportCharset() && statement.Charset != "" {
|
if statement.Engine.dialect.SupportCharset() && statement.Charset != "" {
|
||||||
sql += " DEFAULT CHARSET " + statement.Charset
|
sql += " DEFAULT CHARSET " + statement.Charset
|
||||||
}
|
}
|
||||||
sql += ";"
|
sql += ";"
|
||||||
|
@ -286,9 +286,11 @@ func (s *Statement) genIndexSQL() []string {
|
||||||
tbName := s.TableName()
|
tbName := s.TableName()
|
||||||
quote := s.Engine.Quote
|
quote := s.Engine.Quote
|
||||||
for idxName, index := range s.RefTable.Indexes {
|
for idxName, index := range s.RefTable.Indexes {
|
||||||
sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(tbName, idxName)),
|
if index.Type == IndexType {
|
||||||
quote(tbName), quote(strings.Join(index.GenColsStr(), quote(","))))
|
sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(tbName, idxName)),
|
||||||
sqls = append(sqls, sql)
|
quote(tbName), quote(strings.Join(index.Cols, quote(","))))
|
||||||
|
sqls = append(sqls, sql)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sqls
|
return sqls
|
||||||
}
|
}
|
||||||
|
@ -302,9 +304,11 @@ func (s *Statement) genUniqueSQL() []string {
|
||||||
tbName := s.TableName()
|
tbName := s.TableName()
|
||||||
quote := s.Engine.Quote
|
quote := s.Engine.Quote
|
||||||
for idxName, unique := range s.RefTable.Indexes {
|
for idxName, unique := range s.RefTable.Indexes {
|
||||||
sql := fmt.Sprintf("CREATE UNIQUE INDEX %v ON %v (%v);", quote(uniqueName(tbName, idxName)),
|
if unique.Type == UniqueType {
|
||||||
quote(tbName), quote(strings.Join(unique.GenColsStr(), quote(","))))
|
sql := fmt.Sprintf("CREATE UNIQUE INDEX %v ON %v (%v);", quote(uniqueName(tbName, idxName)),
|
||||||
sqls = append(sqls, sql)
|
quote(tbName), quote(strings.Join(unique.Cols, quote(","))))
|
||||||
|
sqls = append(sqls, sql)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sqls
|
return sqls
|
||||||
}
|
}
|
||||||
|
@ -313,13 +317,13 @@ func (s *Statement) genDelIndexSQL() []string {
|
||||||
var sqls []string = make([]string, 0)
|
var sqls []string = make([]string, 0)
|
||||||
for idxName, index := range s.RefTable.Indexes {
|
for idxName, index := range s.RefTable.Indexes {
|
||||||
var rIdxName string
|
var rIdxName string
|
||||||
if index.IsUnique {
|
if index.Type == UniqueType {
|
||||||
rIdxName = uniqueName(s.TableName(), idxName)
|
rIdxName = uniqueName(s.TableName(), idxName)
|
||||||
} else {
|
} else if index.Type == IndexType {
|
||||||
rIdxName = indexName(s.TableName(), idxName)
|
rIdxName = indexName(s.TableName(), idxName)
|
||||||
}
|
}
|
||||||
sql := fmt.Sprintf("DROP INDEX %v", s.Engine.Quote(rIdxName))
|
sql := fmt.Sprintf("DROP INDEX %v", s.Engine.Quote(rIdxName))
|
||||||
if s.Engine.Dialect.IndexOnTable() {
|
if s.Engine.dialect.IndexOnTable() {
|
||||||
sql += fmt.Sprintf(" ON %v", s.Engine.Quote(s.TableName()))
|
sql += fmt.Sprintf(" ON %v", s.Engine.Quote(s.TableName()))
|
||||||
}
|
}
|
||||||
sqls = append(sqls, sql)
|
sqls = append(sqls, sql)
|
||||||
|
@ -351,7 +355,7 @@ func (statement Statement) genGetSql(bean interface{}) (string, []interface{}) {
|
||||||
func (s *Statement) genAddColumnStr(col *Column) (string, []interface{}) {
|
func (s *Statement) genAddColumnStr(col *Column) (string, []interface{}) {
|
||||||
quote := s.Engine.Quote
|
quote := s.Engine.Quote
|
||||||
sql := fmt.Sprintf("ALTER TABLE %v ADD COLUMN %v;", quote(s.TableName()),
|
sql := fmt.Sprintf("ALTER TABLE %v ADD COLUMN %v;", quote(s.TableName()),
|
||||||
col.String(s.Engine))
|
col.String(s.Engine.dialect))
|
||||||
return sql, []interface{}{}
|
return sql, []interface{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
69
table.go
69
table.go
|
@ -143,35 +143,57 @@ func Type2SQLType(t reflect.Type) (st SQLType) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SQLType2Type(st SQLType) reflect.Type {
|
||||||
|
switch st.Name {
|
||||||
|
case Bit, TinyInt, SmallInt, MediumInt, Int, Integer, Serial:
|
||||||
|
return reflect.TypeOf(1)
|
||||||
|
case BigInt, BigSerial:
|
||||||
|
return reflect.TypeOf(int64(1))
|
||||||
|
case Float, Real:
|
||||||
|
return reflect.TypeOf(float32(1))
|
||||||
|
case Double:
|
||||||
|
return reflect.TypeOf(float64(1))
|
||||||
|
case Char, Varchar, TinyText, Text, MediumText, LongText:
|
||||||
|
return reflect.TypeOf("")
|
||||||
|
case TinyBlob, Blob, LongBlob, Bytea, Binary, MediumBlob, VarBinary:
|
||||||
|
return reflect.TypeOf([]byte{})
|
||||||
|
case Bool:
|
||||||
|
return reflect.TypeOf(true)
|
||||||
|
case DateTime, Date, Time, TimeStamp:
|
||||||
|
return reflect.TypeOf(tm)
|
||||||
|
case Decimal, Numeric:
|
||||||
|
return reflect.TypeOf("")
|
||||||
|
default:
|
||||||
|
return reflect.TypeOf("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TWOSIDES = iota + 1
|
IndexType = iota + 1
|
||||||
ONLYTODB
|
UniqueType
|
||||||
ONLYFROMDB
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Index struct {
|
type Index struct {
|
||||||
Name string
|
Name string
|
||||||
IsUnique bool
|
Type int
|
||||||
Cols []*Column
|
Cols []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (index *Index) AddColumn(cols ...*Column) {
|
func (index *Index) AddColumn(cols ...string) {
|
||||||
for _, col := range cols {
|
for _, col := range cols {
|
||||||
index.Cols = append(index.Cols, col)
|
index.Cols = append(index.Cols, col)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (index *Index) GenColsStr() []string {
|
func NewIndex(name string, indexType int) *Index {
|
||||||
names := make([]string, len(index.Cols))
|
return &Index{name, indexType, make([]string, 0)}
|
||||||
for idx, col := range index.Cols {
|
|
||||||
names[idx] = col.Name
|
|
||||||
}
|
|
||||||
return names
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIndex(name string, isUnique bool) *Index {
|
const (
|
||||||
return &Index{name, isUnique, make([]*Column, 0)}
|
TWOSIDES = iota + 1
|
||||||
}
|
ONLYTODB
|
||||||
|
ONLYFROMDB
|
||||||
|
)
|
||||||
|
|
||||||
type Column struct {
|
type Column struct {
|
||||||
Name string
|
Name string
|
||||||
|
@ -181,26 +203,26 @@ type Column struct {
|
||||||
Length2 int
|
Length2 int
|
||||||
Nullable bool
|
Nullable bool
|
||||||
Default string
|
Default string
|
||||||
Index *Index
|
Indexes map[string]bool
|
||||||
IsPrimaryKey bool
|
IsPrimaryKey bool
|
||||||
IsAutoIncrement bool
|
IsAutoIncrement bool
|
||||||
MapType int
|
MapType int
|
||||||
IsCreated bool
|
IsCreated bool
|
||||||
IsUpdated bool
|
IsUpdated bool
|
||||||
Comment string
|
IsCascade bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (col *Column) String(engine *Engine) string {
|
func (col *Column) String(d dialect) string {
|
||||||
sql := engine.Quote(col.Name) + " "
|
sql := d.QuoteStr() + col.Name + d.QuoteStr() + " "
|
||||||
|
|
||||||
sql += engine.SqlType(col) + " "
|
sql += d.SqlType(col) + " "
|
||||||
|
|
||||||
if col.IsPrimaryKey {
|
if col.IsPrimaryKey {
|
||||||
sql += "PRIMARY KEY "
|
sql += "PRIMARY KEY "
|
||||||
}
|
}
|
||||||
|
|
||||||
if col.IsAutoIncrement {
|
if col.IsAutoIncrement {
|
||||||
sql += engine.AutoIncrStr() + " "
|
sql += d.AutoIncrStr() + " "
|
||||||
}
|
}
|
||||||
|
|
||||||
if col.Nullable {
|
if col.Nullable {
|
||||||
|
@ -213,9 +235,6 @@ func (col *Column) String(engine *Engine) string {
|
||||||
sql += "DEFAULT " + col.Default + " "
|
sql += "DEFAULT " + col.Default + " "
|
||||||
}
|
}
|
||||||
|
|
||||||
if col.Comment != "" {
|
|
||||||
sql += "COMMENT '" + col.Comment + "' "
|
|
||||||
}
|
|
||||||
return sql
|
return sql
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
xorm.go
12
xorm.go
|
@ -10,7 +10,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
version string = "0.1.9"
|
version string = "0.2.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
func close(engine *Engine) {
|
func close(engine *Engine) {
|
||||||
|
@ -24,19 +24,19 @@ func NewEngine(driverName string, dataSourceName string) (*Engine, error) {
|
||||||
DataSourceName: dataSourceName, Filters: make([]Filter, 0)}
|
DataSourceName: dataSourceName, Filters: make([]Filter, 0)}
|
||||||
|
|
||||||
if driverName == SQLITE {
|
if driverName == SQLITE {
|
||||||
engine.Dialect = &sqlite3{}
|
engine.dialect = &sqlite3{}
|
||||||
} else if driverName == MYSQL {
|
} else if driverName == MYSQL {
|
||||||
engine.Dialect = &mysql{}
|
engine.dialect = &mysql{}
|
||||||
} else if driverName == POSTGRES {
|
} else if driverName == POSTGRES {
|
||||||
engine.Dialect = &postgres{}
|
engine.dialect = &postgres{}
|
||||||
engine.Filters = append(engine.Filters, &PgSeqFilter{})
|
engine.Filters = append(engine.Filters, &PgSeqFilter{})
|
||||||
engine.Filters = append(engine.Filters, &QuoteFilter{})
|
engine.Filters = append(engine.Filters, &QuoteFilter{})
|
||||||
} else if driverName == MYMYSQL {
|
} else if driverName == MYMYSQL {
|
||||||
engine.Dialect = &mymysql{}
|
engine.dialect = &mymysql{}
|
||||||
} else {
|
} else {
|
||||||
return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName))
|
return nil, errors.New(fmt.Sprintf("Unsupported driver name: %v", driverName))
|
||||||
}
|
}
|
||||||
err := engine.Dialect.Init(dataSourceName)
|
err := engine.dialect.Init(driverName, dataSourceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
package main
|
|
@ -0,0 +1,78 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A Command is an implementation of a go command
|
||||||
|
// like go build or go fix.
|
||||||
|
type Command struct {
|
||||||
|
// Run runs the command.
|
||||||
|
// The args are the arguments after the command name.
|
||||||
|
Run func(cmd *Command, args []string)
|
||||||
|
|
||||||
|
// UsageLine is the one-line usage message.
|
||||||
|
// The first word in the line is taken to be the command name.
|
||||||
|
UsageLine string
|
||||||
|
|
||||||
|
// Short is the short description shown in the 'go help' output.
|
||||||
|
Short string
|
||||||
|
|
||||||
|
// Long is the long message shown in the 'go help <this-command>' output.
|
||||||
|
Long string
|
||||||
|
|
||||||
|
// Flag is a set of flags specific to this command.
|
||||||
|
Flags map[string]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the command's name: the first word in the usage line.
|
||||||
|
func (c *Command) Name() string {
|
||||||
|
name := c.UsageLine
|
||||||
|
i := strings.Index(name, " ")
|
||||||
|
if i >= 0 {
|
||||||
|
name = name[:i]
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) Usage() {
|
||||||
|
fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
|
||||||
|
fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(c.Long))
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runnable reports whether the command can be run; otherwise
|
||||||
|
// it is a documentation pseudo-command such as importpath.
|
||||||
|
func (c *Command) Runnable() bool {
|
||||||
|
return c.Run != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkFlags checks if the flag exists with correct format.
|
||||||
|
func checkFlags(flags map[string]bool, args []string, print func(string)) int {
|
||||||
|
num := 0 // Number of valid flags, use to cut out.
|
||||||
|
for i, f := range args {
|
||||||
|
// Check flag prefix '-'.
|
||||||
|
if !strings.HasPrefix(f, "-") {
|
||||||
|
// Not a flag, finish check process.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it a valid flag.
|
||||||
|
if v, ok := flags[f]; ok {
|
||||||
|
flags[f] = !v
|
||||||
|
if !v {
|
||||||
|
print(f)
|
||||||
|
} else {
|
||||||
|
fmt.Println("DISABLE: " + f)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Printf("[ERRO] Unknown flag: %s.\n", f)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
num = i + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return num
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/lunny/xorm"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func unTitle(src string) string {
|
||||||
|
if src == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.ToLower(string(src[0])) + src[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func typestring(st xorm.SQLType) string {
|
||||||
|
t := xorm.SQLType2Type(st)
|
||||||
|
s := t.String()
|
||||||
|
if s == "[]uint8" {
|
||||||
|
return "[]byte"
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func tag(table *xorm.Table, col *xorm.Column) string {
|
||||||
|
res := make([]string, 0)
|
||||||
|
if !col.Nullable {
|
||||||
|
res = append(res, "not null")
|
||||||
|
}
|
||||||
|
if col.IsPrimaryKey {
|
||||||
|
res = append(res, "pk")
|
||||||
|
}
|
||||||
|
if col.Default != "" {
|
||||||
|
res = append(res, "default "+col.Default)
|
||||||
|
}
|
||||||
|
if col.IsAutoIncrement {
|
||||||
|
res = append(res, "autoincr")
|
||||||
|
}
|
||||||
|
if col.IsCreated {
|
||||||
|
res = append(res, "created")
|
||||||
|
}
|
||||||
|
if col.IsUpdated {
|
||||||
|
res = append(res, "updated")
|
||||||
|
}
|
||||||
|
for name, _ := range col.Indexes {
|
||||||
|
index := table.Indexes[name]
|
||||||
|
var uistr string
|
||||||
|
if index.Type == xorm.UniqueType {
|
||||||
|
uistr = "unique"
|
||||||
|
} else if index.Type == xorm.IndexType {
|
||||||
|
uistr = "index"
|
||||||
|
}
|
||||||
|
if index.Name != col.Name {
|
||||||
|
uistr += "(" + index.Name + ")"
|
||||||
|
}
|
||||||
|
res = append(res, uistr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(res) > 0 {
|
||||||
|
return "`xorm:\"" + strings.Join(res, " ") + "\"`"
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
if [ ! -f install.sh ]; then
|
||||||
|
echo 'install must be run within its container folder' 1>&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
CURDIR=`pwd`
|
||||||
|
NEWPATH="$GOPATH/src/github.com/lunny/xorm/${PWD##*/}"
|
||||||
|
if [ ! -d "$NEWPATH" ]; then
|
||||||
|
ln -s $CURDIR $NEWPATH
|
||||||
|
fi
|
||||||
|
|
||||||
|
gofmt -w $CURDIR
|
||||||
|
|
||||||
|
cd $NEWPATH
|
||||||
|
go install ${PWD##*/}
|
||||||
|
cd $CURDIR
|
||||||
|
|
||||||
|
echo 'finished'
|
|
@ -0,0 +1,222 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
_ "github.com/bylevel/pq"
|
||||||
|
"github.com/dvirsky/go-pylog/logging"
|
||||||
|
_ "github.com/go-sql-driver/mysql"
|
||||||
|
"github.com/lunny/xorm"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
_ "github.com/ziutek/mymysql/godrv"
|
||||||
|
"go/format"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
var CmdReverse = &Command{
|
||||||
|
UsageLine: "reverse [-m] driverName datasourceName tmplPath [generatedPath]",
|
||||||
|
Short: "reverse a db to codes",
|
||||||
|
Long: `
|
||||||
|
according database's tables and columns to generate codes for Go, C++ and etc.
|
||||||
|
|
||||||
|
-m Generated one go file for every table
|
||||||
|
driverName Database driver name, now supported four: mysql mymysql sqlite3 postgres
|
||||||
|
datasourceName Database connection uri, for detail infomation please visit driver's project page
|
||||||
|
tmplPath Template dir for generated. the default templates dir has provide 1 template
|
||||||
|
generatedPath This parameter is optional, if blank, the default value is model, then will
|
||||||
|
generated all codes in model dir
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
CmdReverse.Run = runReverse
|
||||||
|
CmdReverse.Flags = map[string]bool{
|
||||||
|
"-m": false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func printReversePrompt(flag string) {
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tmpl struct {
|
||||||
|
Tables []*xorm.Table
|
||||||
|
Imports map[string]string
|
||||||
|
Model string
|
||||||
|
}
|
||||||
|
|
||||||
|
func runReverse(cmd *Command, args []string) {
|
||||||
|
num := checkFlags(cmd.Flags, args, printReversePrompt)
|
||||||
|
if num == -1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
args = args[num:]
|
||||||
|
|
||||||
|
if len(args) < 3 {
|
||||||
|
fmt.Println("no")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var isMultiFile bool
|
||||||
|
if _, ok := cmd.Flags["-m"]; ok {
|
||||||
|
isMultiFile = true
|
||||||
|
}
|
||||||
|
|
||||||
|
curPath, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(curPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var genDir string
|
||||||
|
var model string
|
||||||
|
if len(args) == 4 {
|
||||||
|
genDir, err = filepath.Abs(args[3])
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
model = path.Base(genDir)
|
||||||
|
} else {
|
||||||
|
model = "model"
|
||||||
|
genDir = path.Join(curPath, model)
|
||||||
|
}
|
||||||
|
|
||||||
|
os.MkdirAll(genDir, os.ModePerm)
|
||||||
|
|
||||||
|
Orm, err := xorm.NewEngine(args[0], args[1])
|
||||||
|
if err != nil {
|
||||||
|
logging.Error("%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tables, err := Orm.DBMetas()
|
||||||
|
if err != nil {
|
||||||
|
logging.Error("%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dir, err := filepath.Abs(args[2])
|
||||||
|
if err != nil {
|
||||||
|
logging.Error("%v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m := &xorm.SnakeMapper{}
|
||||||
|
|
||||||
|
filepath.Walk(dir, func(f string, info os.FileInfo, err error) error {
|
||||||
|
if info.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
bs, err := ioutil.ReadFile(f)
|
||||||
|
if err != nil {
|
||||||
|
logging.Error("%v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t := template.New(f)
|
||||||
|
t.Funcs(template.FuncMap{"Mapper": m.Table2Obj,
|
||||||
|
"Type": typestring,
|
||||||
|
"Tag": tag,
|
||||||
|
})
|
||||||
|
|
||||||
|
tmpl, err := t.Parse(string(bs))
|
||||||
|
if err != nil {
|
||||||
|
logging.Error("%v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var w *os.File
|
||||||
|
fileName := info.Name()
|
||||||
|
newFileName := fileName[:len(fileName)-4]
|
||||||
|
ext := path.Ext(newFileName)
|
||||||
|
|
||||||
|
if !isMultiFile {
|
||||||
|
w, err = os.OpenFile(path.Join(genDir, newFileName), os.O_RDWR|os.O_CREATE, 0600)
|
||||||
|
if err != nil {
|
||||||
|
logging.Error("%v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
imports := make(map[string]string)
|
||||||
|
tbls := make([]*xorm.Table, 0)
|
||||||
|
for _, table := range tables {
|
||||||
|
for _, col := range table.Columns {
|
||||||
|
if typestring(col.SQLType) == "time.Time" {
|
||||||
|
imports["time"] = "time"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tbls = append(tbls, table)
|
||||||
|
}
|
||||||
|
|
||||||
|
newbytes := bytes.NewBufferString("")
|
||||||
|
|
||||||
|
t := &Tmpl{Tables: tbls, Imports: imports, Model: model}
|
||||||
|
err = tmpl.Execute(newbytes, t)
|
||||||
|
if err != nil {
|
||||||
|
logging.Error("%v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tplcontent, err := ioutil.ReadAll(newbytes)
|
||||||
|
if err != nil {
|
||||||
|
logging.Error("%v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
source, err := format.Source(tplcontent)
|
||||||
|
if err != nil {
|
||||||
|
logging.Error("%v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteString(string(source))
|
||||||
|
w.Close()
|
||||||
|
} else {
|
||||||
|
for _, table := range tables {
|
||||||
|
// imports
|
||||||
|
imports := make(map[string]string)
|
||||||
|
for _, col := range table.Columns {
|
||||||
|
if typestring(col.SQLType) == "time.Time" {
|
||||||
|
imports["time"] = "time"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w, err := os.OpenFile(path.Join(genDir, unTitle(m.Table2Obj(table.Name))+ext), os.O_RDWR|os.O_CREATE, 0600)
|
||||||
|
if err != nil {
|
||||||
|
logging.Error("%v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
newbytes := bytes.NewBufferString("")
|
||||||
|
|
||||||
|
t := &Tmpl{Tables: []*xorm.Table{table}, Imports: imports, Model: model}
|
||||||
|
err = tmpl.Execute(newbytes, t)
|
||||||
|
if err != nil {
|
||||||
|
logging.Error("%v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
tplcontent, err := ioutil.ReadAll(newbytes)
|
||||||
|
if err != nil {
|
||||||
|
logging.Error("%v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
source, err := format.Source(tplcontent)
|
||||||
|
if err != nil {
|
||||||
|
logging.Error("%v", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteString(string(source))
|
||||||
|
w.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package {{.Model}}
|
||||||
|
|
||||||
|
import (
|
||||||
|
{{range .Imports}}"{{.}}"{{end}}
|
||||||
|
)
|
||||||
|
|
||||||
|
{{range .Tables}}
|
||||||
|
type {{Mapper .Name}} struct {
|
||||||
|
{{$table := .}}
|
||||||
|
{{range .Columns}} {{Mapper .Name}} {{Type .SQLType}} {{Tag $table .}}
|
||||||
|
{{end}}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{end}}
|
|
@ -0,0 +1,160 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/dvirsky/go-pylog/logging"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"text/template"
|
||||||
|
"unicode"
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// +build go1.1
|
||||||
|
|
||||||
|
// Test that go1.1 tag above is included in builds. main.go refers to this definition.
|
||||||
|
const go11tag = true
|
||||||
|
|
||||||
|
// Commands lists the available commands and help topics.
|
||||||
|
// The order here is the order in which they are printed by 'gopm help'.
|
||||||
|
var commands = []*Command{
|
||||||
|
CmdReverse,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
logging.SetLevel(logging.ALL)
|
||||||
|
// Check length of arguments.
|
||||||
|
args := os.Args[1:]
|
||||||
|
if len(args) < 1 {
|
||||||
|
usage()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show help documentation.
|
||||||
|
if args[0] == "help" {
|
||||||
|
help(args[1:])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check commands and run.
|
||||||
|
for _, comm := range commands {
|
||||||
|
if comm.Name() == args[0] && comm.Run != nil {
|
||||||
|
comm.Run(comm, args[1:])
|
||||||
|
exit()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, "xorm: unknown subcommand %q\nRun 'xorm help' for usage.\n", args[0])
|
||||||
|
setExitStatus(2)
|
||||||
|
exit()
|
||||||
|
}
|
||||||
|
|
||||||
|
var exitStatus = 0
|
||||||
|
var exitMu sync.Mutex
|
||||||
|
|
||||||
|
func setExitStatus(n int) {
|
||||||
|
exitMu.Lock()
|
||||||
|
if exitStatus < n {
|
||||||
|
exitStatus = n
|
||||||
|
}
|
||||||
|
exitMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
var usageTemplate = `xorm is a database tool based xorm package.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
xorm command [arguments]
|
||||||
|
|
||||||
|
The commands are:
|
||||||
|
{{range .}}{{if .Runnable}}
|
||||||
|
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
|
||||||
|
|
||||||
|
Use "xorm help [command]" for more information about a command.
|
||||||
|
|
||||||
|
Additional help topics:
|
||||||
|
{{range .}}{{if not .Runnable}}
|
||||||
|
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
|
||||||
|
|
||||||
|
Use "xorm help [topic]" for more information about that topic.
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
|
||||||
|
|
||||||
|
{{end}}{{.Long | trim}}
|
||||||
|
`
|
||||||
|
|
||||||
|
// tmpl executes the given template text on data, writing the result to w.
|
||||||
|
func tmpl(w io.Writer, text string, data interface{}) {
|
||||||
|
t := template.New("top")
|
||||||
|
t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
|
||||||
|
template.Must(t.Parse(text))
|
||||||
|
if err := t.Execute(w, data); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func capitalize(s string) string {
|
||||||
|
if s == "" {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
r, n := utf8.DecodeRuneInString(s)
|
||||||
|
return string(unicode.ToTitle(r)) + s[n:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func printUsage(w io.Writer) {
|
||||||
|
tmpl(w, usageTemplate, commands)
|
||||||
|
}
|
||||||
|
|
||||||
|
func usage() {
|
||||||
|
printUsage(os.Stderr)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// help implements the 'help' command.
|
||||||
|
func help(args []string) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
printUsage(os.Stdout)
|
||||||
|
// not exit 2: succeeded at 'gopm help'.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(args) != 1 {
|
||||||
|
fmt.Fprintf(os.Stderr, "usage: xorm help command\n\nToo many arguments given.\n")
|
||||||
|
os.Exit(2) // failed at 'gopm help'
|
||||||
|
}
|
||||||
|
|
||||||
|
arg := args[0]
|
||||||
|
|
||||||
|
for _, cmd := range commands {
|
||||||
|
if cmd.Name() == arg {
|
||||||
|
tmpl(os.Stdout, helpTemplate, cmd)
|
||||||
|
// not exit 2: succeeded at 'gopm help cmd'.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(os.Stderr, "Unknown help topic %#q. Run 'xorm help'.\n", arg)
|
||||||
|
os.Exit(2) // failed at 'gopm help cmd'
|
||||||
|
}
|
||||||
|
|
||||||
|
var atexitFuncs []func()
|
||||||
|
|
||||||
|
func atexit(f func()) {
|
||||||
|
atexitFuncs = append(atexitFuncs, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func exit() {
|
||||||
|
for _, f := range atexitFuncs {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
os.Exit(exitStatus)
|
||||||
|
}
|
Loading…
Reference in New Issue