1
0
mirror of https://github.com/astaxie/beego.git synced 2024-11-25 20:10:56 +00:00

orm support auto create db

This commit is contained in:
slene 2013-08-19 22:37:39 +08:00
parent 1fedaf21ec
commit c38abf35da
16 changed files with 470 additions and 397 deletions

144
orm/cmd.go Normal file
View File

@ -0,0 +1,144 @@
package orm
import (
"flag"
"fmt"
"os"
"strings"
)
type commander interface {
Parse([]string)
Run()
}
var (
commands = make(map[string]commander)
)
func printHelp(errs ...string) {
content := `orm command usage:
syncdb - auto create tables
sqlall - print sql of create tables
help - print this help
`
if len(errs) > 0 {
fmt.Println(errs[0])
}
fmt.Println(content)
os.Exit(2)
}
func RunCommand() {
if len(os.Args) < 2 || os.Args[1] != "orm" {
return
}
BootStrap()
args := argString(os.Args[2:])
name := args.Get(0)
if name == "help" {
printHelp()
}
if cmd, ok := commands[name]; ok {
cmd.Parse(os.Args[3:])
cmd.Run()
os.Exit(0)
} else {
if name == "" {
printHelp()
} else {
printHelp(fmt.Sprintf("unknown command %s", name))
}
}
}
type commandSyncDb struct {
al *alias
force bool
verbose bool
}
func (d *commandSyncDb) Parse(args []string) {
var name string
flagSet := flag.NewFlagSet("orm command: syncdb", flag.ExitOnError)
flagSet.StringVar(&name, "db", "default", "DataBase alias name")
flagSet.BoolVar(&d.force, "force", false, "drop tables before create")
flagSet.BoolVar(&d.verbose, "v", false, "verbose info")
flagSet.Parse(args)
d.al = getDbAlias(name)
}
func (d *commandSyncDb) Run() {
var drops []string
if d.force {
drops = getDbDropSql(d.al)
}
db := d.al.DB
if d.force {
for i, mi := range modelCache.allOrdered() {
query := drops[i]
_, err := db.Exec(query)
result := ""
if err != nil {
result = err.Error()
}
fmt.Printf("drop table `%s` %s\n", mi.table, result)
if d.verbose {
fmt.Printf(" %s\n\n", query)
}
}
}
tables := getDbCreateSql(d.al)
for i, mi := range modelCache.allOrdered() {
query := tables[i]
_, err := db.Exec(query)
fmt.Printf("create table `%s` \n", mi.table)
if d.verbose {
query = " " + strings.Join(strings.Split(query, "\n"), "\n ")
fmt.Println(query)
}
if err != nil {
fmt.Printf(" %s\n", err.Error())
}
if d.verbose {
fmt.Println("")
}
}
}
type commandSqlAll struct {
al *alias
}
func (d *commandSqlAll) Parse(args []string) {
var name string
flagSet := flag.NewFlagSet("orm command: sqlall", flag.ExitOnError)
flagSet.StringVar(&name, "db", "default", "DataBase alias name")
flagSet.Parse(args)
d.al = getDbAlias(name)
}
func (d *commandSqlAll) Run() {
sqls := getDbCreateSql(d.al)
sql := strings.Join(sqls, "\n\n")
fmt.Println(sql)
}
func init() {
commands["syncdb"] = new(commandSyncDb)
commands["sqlall"] = new(commandSqlAll)
}

142
orm/cmd_utils.go Normal file
View File

@ -0,0 +1,142 @@
package orm
import (
"fmt"
"os"
"strings"
)
func getDbAlias(name string) *alias {
if al, ok := dataBaseCache.get(name); ok {
return al
} else {
fmt.Println(fmt.Sprintf("unknown DataBase alias name %s", name))
os.Exit(2)
}
return nil
}
func getDbDropSql(al *alias) (sqls []string) {
if len(modelCache.cache) == 0 {
fmt.Println("no Model found, need register your model")
os.Exit(2)
}
Q := al.DbBaser.TableQuote()
for _, mi := range modelCache.allOrdered() {
sqls = append(sqls, fmt.Sprintf(`DROP TABLE IF EXISTS %s%s%s`, Q, mi.table, Q))
}
return sqls
}
func getDbCreateSql(al *alias) (sqls []string) {
if len(modelCache.cache) == 0 {
fmt.Println("no Model found, need register your model")
os.Exit(2)
}
Q := al.DbBaser.TableQuote()
T := al.DbBaser.DbTypes()
for _, mi := range modelCache.allOrdered() {
sql := fmt.Sprintf("-- %s\n", strings.Repeat("-", 50))
sql += fmt.Sprintf("-- Table Structure for `%s`\n", mi.fullName)
sql += fmt.Sprintf("-- %s\n", strings.Repeat("-", 50))
sql += fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s%s%s (\n", Q, mi.table, Q)
columns := make([]string, 0, len(mi.fields.fieldsDB))
for _, fi := range mi.fields.fieldsDB {
fieldType := fi.fieldType
column := fmt.Sprintf(" %s%s%s ", Q, fi.column, Q)
col := ""
checkColumn:
switch fieldType {
case TypeBooleanField:
col = T["bool"]
case TypeCharField:
col = fmt.Sprintf(T["string"], fi.size)
case TypeTextField:
col = T["string-text"]
case TypeDateField:
col = T["time.Time-date"]
case TypeDateTimeField:
col = T["time.Time"]
case TypeBitField:
col = T["int8"]
case TypeSmallIntegerField:
col = T["int16"]
case TypeIntegerField:
col = T["int32"]
case TypeBigIntegerField:
if al.Driver == DR_Sqlite {
fieldType = TypeIntegerField
goto checkColumn
}
col = T["int64"]
case TypePositiveBitField:
col = T["uint8"]
case TypePositiveSmallIntegerField:
col = T["uint16"]
case TypePositiveIntegerField:
col = T["uint32"]
case TypePositiveBigIntegerField:
col = T["uint64"]
case TypeFloatField:
col = T["float64"]
case TypeDecimalField:
s := T["float64-decimal"]
if strings.Index(s, "%d") == -1 {
col = s
} else {
col = fmt.Sprintf(s, fi.digits, fi.decimals)
}
case RelForeignKey, RelOneToOne:
fieldType = fi.relModelInfo.fields.pk.fieldType
goto checkColumn
}
if fi.auto {
if al.Driver == DR_Postgres {
column += T["auto"]
} else {
column += col + " " + T["auto"]
}
} else if fi.pk {
column += col + " " + T["pk"]
} else {
column += col
if fi.null == false {
column += " " + "NOT NULL"
}
if fi.unique {
column += " " + "UNIQUE"
}
}
if strings.Index(column, "%COL%") != -1 {
column = strings.Replace(column, "%COL%", fi.column, -1)
}
columns = append(columns, column)
}
sql += strings.Join(columns, ",\n")
sql += "\n)"
if al.Driver == DR_MySQL {
sql += " ENGINE=INNODB"
}
sqls = append(sqls, sql)
}
return sqls
}

View File

@ -1,44 +0,0 @@
package orm
import (
"flag"
"fmt"
"os"
)
func printHelp() {
}
func getSqlAll() (sql string) {
for _, mi := range modelCache.allOrdered() {
_ = mi
}
return
}
func runCommand() {
if len(os.Args) < 2 || os.Args[1] != "orm" {
return
}
_ = flag.NewFlagSet("orm command", flag.ExitOnError)
args := argString(os.Args[2:])
cmd := args.Get(0)
switch cmd {
case "syncdb":
case "sqlall":
sql := getSqlAll()
fmt.Println(sql)
default:
if cmd != "" {
fmt.Printf("unknown command %s", cmd)
} else {
printHelp()
}
os.Exit(2)
}
}

View File

@ -805,7 +805,7 @@ setValue:
_, err = str.Int32() _, err = str.Int32()
case TypeBigIntegerField: case TypeBigIntegerField:
_, err = str.Int64() _, err = str.Int64()
case TypePostiveBitField: case TypePositiveBitField:
_, err = str.Uint8() _, err = str.Uint8()
case TypePositiveSmallIntegerField: case TypePositiveSmallIntegerField:
_, err = str.Uint16() _, err = str.Uint16()
@ -1112,3 +1112,7 @@ func (d *dbBase) TimeFromDB(t *time.Time, tz *time.Location) {
func (d *dbBase) TimeToDB(t *time.Time, tz *time.Location) { func (d *dbBase) TimeToDB(t *time.Time, tz *time.Location) {
*t = t.In(tz) *t = t.In(tz)
} }
func (d *dbBase) DbTypes() map[string]string {
return nil
}

View File

@ -17,6 +17,26 @@ var mysqlOperators = map[string]string{
"iendswith": "LIKE ?", "iendswith": "LIKE ?",
} }
var mysqlTypes = map[string]string{
"auto": "AUTO_INCREMENT NOT NULL PRIMARY KEY",
"pk": "NOT NULL PRIMARY KEY",
"bool": "bool",
"string": "varchar(%d)",
"string-text": "longtext",
"time.Time-date": "date",
"time.Time": "datetime",
"int8": "tinyint",
"int16": "smallint",
"int32": "integer",
"int64": "bigint",
"uint8": "tinyint unsigned",
"uint16": "smallint unsigned",
"uint32": "integer unsigned",
"uint64": "bigint unsigned",
"float64": "double precision",
"float64-decimal": "numeric(%d, %d)",
}
type dbBaseMysql struct { type dbBaseMysql struct {
dbBase dbBase
} }
@ -27,6 +47,10 @@ func (d *dbBaseMysql) OperatorSql(operator string) string {
return mysqlOperators[operator] return mysqlOperators[operator]
} }
func (d *dbBaseMysql) DbTypes() map[string]string {
return mysqlTypes
}
func newdbBaseMysql() dbBaser { func newdbBaseMysql() dbBaser {
b := new(dbBaseMysql) b := new(dbBaseMysql)
b.ins = b b.ins = b

View File

@ -20,6 +20,26 @@ var postgresOperators = map[string]string{
"iendswith": "LIKE UPPER(?)", "iendswith": "LIKE UPPER(?)",
} }
var postgresTypes = map[string]string{
"auto": "serial NOT NULL PRIMARY KEY",
"pk": "NOT NULL PRIMARY KEY",
"bool": "bool",
"string": "varchar(%d)",
"string-text": "text",
"time.Time-date": "date",
"time.Time": "timestamp with time zone",
"int8": `smallint CHECK("%COL%" >= -127 AND "%COL%" <= 128)`,
"int16": "smallint",
"int32": "integer",
"int64": "bigint",
"uint8": `smallint CHECK("%COL%" >= 0 AND "%COL%" <= 255)`,
"uint16": `integer CHECK("%COL%" >= 0)`,
"uint32": `bigint CHECK("%COL%" >= 0)`,
"uint64": `bigint CHECK("%COL%" >= 0)`,
"float64": "double precision",
"float64-decimal": "numeric(%d, %d)",
}
type dbBasePostgres struct { type dbBasePostgres struct {
dbBase dbBase
} }
@ -87,6 +107,10 @@ func (d *dbBasePostgres) HasReturningID(mi *modelInfo, query *string) (has bool)
return return
} }
func (d *dbBasePostgres) DbTypes() map[string]string {
return postgresTypes
}
func newdbBasePostgres() dbBaser { func newdbBasePostgres() dbBaser {
b := new(dbBasePostgres) b := new(dbBasePostgres)
b.ins = b b.ins = b

View File

@ -19,6 +19,26 @@ var sqliteOperators = map[string]string{
"iendswith": "LIKE ? ESCAPE '\\'", "iendswith": "LIKE ? ESCAPE '\\'",
} }
var sqliteTypes = map[string]string{
"auto": "NOT NULL PRIMARY KEY AUTOINCREMENT",
"pk": "NOT NULL PRIMARY KEY",
"bool": "bool",
"string": "varchar(%d)",
"string-text": "text",
"time.Time-date": "date",
"time.Time": "datetime",
"int8": "tinyint",
"int16": "smallint",
"int32": "integer",
"int64": "bigint",
"uint8": "tinyint unsigned",
"uint16": "smallint unsigned",
"uint32": "integer unsigned",
"uint64": "bigint unsigned",
"float64": "real",
"float64-decimal": "decimal",
}
type dbBaseSqlite struct { type dbBaseSqlite struct {
dbBase dbBase
} }
@ -43,6 +63,10 @@ func (d *dbBaseSqlite) MaxLimit() uint64 {
return 9223372036854775807 return 9223372036854775807
} }
func (d *dbBaseSqlite) DbTypes() map[string]string {
return sqliteTypes
}
func newdbBaseSqlite() dbBaser { func newdbBaseSqlite() dbBaser {
b := new(dbBaseSqlite) b := new(dbBaseSqlite)
b.ins = b b.ins = b

View File

@ -84,3 +84,10 @@ func (mc *_modelCache) set(table string, mi *modelInfo) *modelInfo {
} }
return mii return mii
} }
func (mc *_modelCache) clean() {
mc.orders = make([]string, 0)
mc.cache = make(map[string]*modelInfo)
mc.cacheByFN = make(map[string]*modelInfo)
mc.done = false
}

View File

@ -8,7 +8,7 @@ import (
"strings" "strings"
) )
func registerModel(model interface{}) { func registerModel(model interface{}, prefix string) {
val := reflect.ValueOf(model) val := reflect.ValueOf(model)
ind := reflect.Indirect(val) ind := reflect.Indirect(val)
typ := ind.Type() typ := ind.Type()
@ -17,20 +17,25 @@ func registerModel(model interface{}) {
panic(fmt.Sprintf("<orm.RegisterModel> cannot use non-ptr model struct `%s`", getFullName(typ))) panic(fmt.Sprintf("<orm.RegisterModel> cannot use non-ptr model struct `%s`", getFullName(typ)))
} }
info := newModelInfo(val) table := getTableName(val)
if prefix != "" {
table = prefix + table
}
name := getFullName(typ) name := getFullName(typ)
if _, ok := modelCache.getByFN(name); ok { if _, ok := modelCache.getByFN(name); ok {
fmt.Printf("<orm.RegisterModel> model `%s` redeclared, must be unique\n", name) fmt.Printf("<orm.RegisterModel> model `%s` repeat register, must be unique\n", name)
os.Exit(2) os.Exit(2)
} }
table := getTableName(val)
if _, ok := modelCache.get(table); ok { if _, ok := modelCache.get(table); ok {
fmt.Printf("<orm.RegisterModel> table name `%s` redeclared, must be unique\n", table) fmt.Printf("<orm.RegisterModel> table name `%s` repeat register, must be unique\n", table)
os.Exit(2) os.Exit(2)
} }
info := newModelInfo(val)
if info.fields.pk == nil { if info.fields.pk == nil {
outFor: outFor:
for _, fi := range info.fields.fieldsDB { for _, fi := range info.fields.fieldsDB {
@ -58,6 +63,7 @@ func registerModel(model interface{}) {
info.pkg = typ.PkgPath() info.pkg = typ.PkgPath()
info.model = model info.model = model
info.manual = true info.manual = true
modelCache.set(table, info) modelCache.set(table, info)
} }
@ -72,7 +78,7 @@ func bootStrap() {
) )
if dataBaseCache.getDefault() == nil { if dataBaseCache.getDefault() == nil {
err = fmt.Errorf("must have one register alias named `default`") err = fmt.Errorf("must have one register DataBase alias named `default`")
goto end goto end
} }
@ -97,7 +103,7 @@ func bootStrap() {
switch fi.fieldType { switch fi.fieldType {
case RelManyToMany: case RelManyToMany:
if fi.relThrough != "" { if fi.relThrough != "" {
msg := fmt.Sprintf("filed `%s` wrong rel_through value `%s`", fi.fullName, fi.relThrough) msg := fmt.Sprintf("field `%s` wrong rel_through value `%s`", fi.fullName, fi.relThrough)
if i := strings.LastIndex(fi.relThrough, "."); i != -1 && len(fi.relThrough) > (i+1) { if i := strings.LastIndex(fi.relThrough, "."); i != -1 && len(fi.relThrough) > (i+1) {
pn := fi.relThrough[:i] pn := fi.relThrough[:i]
mn := fi.relThrough[i+1:] mn := fi.relThrough[i+1:]
@ -238,11 +244,22 @@ end:
func RegisterModel(models ...interface{}) { func RegisterModel(models ...interface{}) {
if modelCache.done { if modelCache.done {
panic(fmt.Errorf("RegisterModel must be run begore BootStrap")) panic(fmt.Errorf("RegisterModel must be run before BootStrap"))
} }
for _, model := range models { for _, model := range models {
registerModel(model) registerModel(model, "")
}
}
// register model with a prefix
func RegisterModelWithPrefix(prefix string, models ...interface{}) {
if modelCache.done {
panic(fmt.Errorf("RegisterModel must be run before BootStrap"))
}
for _, model := range models {
registerModel(model, prefix)
} }
} }

View File

@ -31,7 +31,7 @@ const (
// int64 // int64
TypeBigIntegerField TypeBigIntegerField
// uint8 // uint8
TypePostiveBitField TypePositiveBitField
// uint16 // uint16
TypePositiveSmallIntegerField TypePositiveSmallIntegerField
// uint32 // uint32

View File

@ -399,7 +399,7 @@ checkType:
_, err = v.Int32() _, err = v.Int32()
case TypeBigIntegerField: case TypeBigIntegerField:
_, err = v.Int64() _, err = v.Int64()
case TypePostiveBitField: case TypePositiveBitField:
_, err = v.Uint8() _, err = v.Uint8()
case TypePositiveSmallIntegerField: case TypePositiveSmallIntegerField:
_, err = v.Uint16() _, err = v.Uint16()

View File

@ -90,6 +90,9 @@ func newM2MModelInfo(m1, m2 *modelInfo) (info *modelInfo) {
fa.auto = true fa.auto = true
fa.pk = true fa.pk = true
fa.dbcol = true fa.dbcol = true
fa.name = "Id"
fa.column = "id"
fa.fullName = info.fullName + "." + fa.name
f1.dbcol = true f1.dbcol = true
f2.dbcol = true f2.dbcol = true

View File

@ -3,10 +3,8 @@ package orm
import ( import (
"fmt" "fmt"
"os" "os"
"strings"
"time" "time"
// _ "github.com/bylevel/pq"
_ "github.com/go-sql-driver/mysql" _ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq" _ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3" _ "github.com/mattn/go-sqlite3"
@ -153,325 +151,7 @@ var (
var dORM Ormer var dORM Ormer
var initSQLs = map[string]string{
"mysql": "DROP TABLE IF EXISTS `user_profile`;\n" +
"DROP TABLE IF EXISTS `user`;\n" +
"DROP TABLE IF EXISTS `post`;\n" +
"DROP TABLE IF EXISTS `tag`;\n" +
"DROP TABLE IF EXISTS `post_tags`;\n" +
"DROP TABLE IF EXISTS `comment`;\n" +
"DROP TABLE IF EXISTS `data`;\n" +
"DROP TABLE IF EXISTS `data_null`;\n" +
"CREATE TABLE `user_profile` (\n" +
" `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
" `age` smallint NOT NULL,\n" +
" `money` double precision NOT NULL\n" +
") ENGINE=INNODB;\n" +
"CREATE TABLE `user` (\n" +
" `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
" `user_name` varchar(30) NOT NULL UNIQUE,\n" +
" `email` varchar(100) NOT NULL,\n" +
" `password` varchar(100) NOT NULL,\n" +
" `status` smallint NOT NULL,\n" +
" `is_staff` bool NOT NULL,\n" +
" `is_active` bool NOT NULL,\n" +
" `created` date NOT NULL,\n" +
" `updated` datetime NOT NULL,\n" +
" `profile_id` integer\n" +
") ENGINE=INNODB;\n" +
"CREATE TABLE `post` (\n" +
" `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
" `user_id` integer NOT NULL,\n" +
" `title` varchar(60) NOT NULL,\n" +
" `content` longtext NOT NULL,\n" +
" `created` datetime NOT NULL,\n" +
" `updated` datetime NOT NULL\n" +
") ENGINE=INNODB;\n" +
"CREATE TABLE `tag` (\n" +
" `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
" `name` varchar(30) NOT NULL\n" +
") ENGINE=INNODB;\n" +
"CREATE TABLE `post_tags` (\n" +
" `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
" `post_id` integer NOT NULL,\n" +
" `tag_id` integer NOT NULL,\n" +
" UNIQUE (`post_id`, `tag_id`)\n" +
") ENGINE=INNODB;\n" +
"CREATE TABLE `comment` (\n" +
" `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
" `post_id` integer NOT NULL,\n" +
" `content` longtext NOT NULL,\n" +
" `parent_id` integer,\n" +
" `created` datetime NOT NULL\n" +
") ENGINE=INNODB;\n" +
"CREATE TABLE `data` (\n" +
" `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
" `boolean` bool NOT NULL,\n" +
" `char` varchar(50) NOT NULL,\n" +
" `text` longtext NOT NULL,\n" +
" `date` date NOT NULL,\n" +
" `date_time` datetime NOT NULL,\n" +
" `byte` tinyint unsigned NOT NULL,\n" +
" `rune` integer NOT NULL,\n" +
" `int` integer NOT NULL,\n" +
" `int8` tinyint NOT NULL,\n" +
" `int16` smallint NOT NULL,\n" +
" `int32` integer NOT NULL,\n" +
" `int64` bigint NOT NULL,\n" +
" `uint` integer unsigned NOT NULL,\n" +
" `uint8` tinyint unsigned NULL,\n" +
" `uint16` smallint unsigned NOT NULL,\n" +
" `uint32` integer unsigned NOT NULL,\n" +
" `uint64` bigint unsigned NOT NULL,\n" +
" `float32` double precision NOT NULL,\n" +
" `float64` double precision NOT NULL,\n" +
" `decimal` numeric(8,4) NOT NULL\n" +
") ENGINE=INNODB;\n" +
"CREATE TABLE `data_null` (\n" +
" `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
" `boolean` bool,\n" +
" `char` varchar(50),\n" +
" `text` longtext,\n" +
" `date` date,\n" +
" `date_time` datetime,\n" +
" `byte` tinyint unsigned,\n" +
" `rune` integer,\n" +
" `int` integer,\n" +
" `int8` tinyint,\n" +
" `int16` smallint,\n" +
" `int32` integer,\n" +
" `int64` bigint,\n" +
" `uint` integer unsigned,\n" +
" `uint8` tinyint unsigned,\n" +
" `uint16` smallint unsigned,\n" +
" `uint32` integer unsigned,\n" +
" `uint64` bigint unsigned,\n" +
" `float32` double precision,\n" +
" `float64` double precision,\n" +
" `decimal` numeric(8,4)\n" +
") ENGINE=INNODB;\n" +
"CREATE INDEX `user_141c6eec` ON `user` (`profile_id`);\n" +
"CREATE INDEX `post_fbfc09f1` ON `post` (`user_id`);\n" +
"CREATE INDEX `comment_699ae8ca` ON `comment` (`post_id`);\n" +
"CREATE INDEX `comment_63f17a16` ON `comment` (`parent_id`);",
"sqlite3": `
DROP TABLE IF EXISTS "user_profile";
DROP TABLE IF EXISTS "user";
DROP TABLE IF EXISTS "post";
DROP TABLE IF EXISTS "tag";
DROP TABLE IF EXISTS "post_tags";
DROP TABLE IF EXISTS "comment";
DROP TABLE IF EXISTS "data";
DROP TABLE IF EXISTS "data_null";
CREATE TABLE "user_profile" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"age" smallint NOT NULL,
"money" real NOT NULL
);
CREATE TABLE "user" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"user_name" varchar(30) NOT NULL UNIQUE,
"email" varchar(100) NOT NULL,
"password" varchar(100) NOT NULL,
"status" smallint NOT NULL,
"is_staff" bool NOT NULL,
"is_active" bool NOT NULL,
"created" date NOT NULL,
"updated" datetime NOT NULL,
"profile_id" integer
);
CREATE TABLE "post" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"user_id" integer NOT NULL,
"title" varchar(60) NOT NULL,
"content" text NOT NULL,
"created" datetime NOT NULL,
"updated" datetime NOT NULL
);
CREATE TABLE "tag" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" varchar(30) NOT NULL
);
CREATE TABLE "post_tags" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"post_id" integer NOT NULL,
"tag_id" integer NOT NULL,
UNIQUE ("post_id", "tag_id")
);
CREATE TABLE "comment" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"post_id" integer NOT NULL,
"content" text NOT NULL,
"parent_id" integer,
"created" datetime NOT NULL
);
CREATE TABLE "data" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"boolean" bool NOT NULL,
"char" varchar(50) NOT NULL,
"text" text NOT NULL,
"date" date NOT NULL,
"date_time" datetime NOT NULL,
"byte" tinyint unsigned NOT NULL,
"rune" integer NOT NULL,
"int" integer NOT NULL,
"int8" tinyint NOT NULL,
"int16" smallint NOT NULL,
"int32" integer NOT NULL,
"int64" bigint NOT NULL,
"uint" integer unsigned NOT NULL,
"uint8" tinyint unsigned NOT NULL,
"uint16" smallint unsigned NOT NULL,
"uint32" integer unsigned NOT NULL,
"uint64" bigint unsigned NOT NULL,
"float32" real NOT NULL,
"float64" real NOT NULL,
"decimal" decimal
);
CREATE TABLE "data_null" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"boolean" bool,
"char" varchar(50),
"text" text,
"date" date,
"date_time" datetime,
"byte" tinyint unsigned,
"rune" integer,
"int" integer,
"int8" tinyint,
"int16" smallint,
"int32" integer,
"int64" bigint,
"uint" integer unsigned,
"uint8" tinyint unsigned,
"uint16" smallint unsigned,
"uint32" integer unsigned,
"uint64" bigint unsigned,
"float32" real,
"float64" real,
"decimal" decimal
);
CREATE INDEX "user_141c6eec" ON "user" ("profile_id");
CREATE INDEX "post_fbfc09f1" ON "post" ("user_id");
CREATE INDEX "comment_699ae8ca" ON "comment" ("post_id");
CREATE INDEX "comment_63f17a16" ON "comment" ("parent_id");
`,
"postgres": `
DROP TABLE IF EXISTS "user_profile";
DROP TABLE IF EXISTS "user";
DROP TABLE IF EXISTS "post";
DROP TABLE IF EXISTS "tag";
DROP TABLE IF EXISTS "post_tags";
DROP TABLE IF EXISTS "comment";
DROP TABLE IF EXISTS "data";
DROP TABLE IF EXISTS "data_null";
CREATE TABLE "user_profile" (
"id" serial NOT NULL PRIMARY KEY,
"age" smallint NOT NULL,
"money" double precision NOT NULL
);
CREATE TABLE "user" (
"id" serial NOT NULL PRIMARY KEY,
"user_name" varchar(30) NOT NULL UNIQUE,
"email" varchar(100) NOT NULL,
"password" varchar(100) NOT NULL,
"status" smallint NOT NULL,
"is_staff" boolean NOT NULL,
"is_active" boolean NOT NULL,
"created" date NOT NULL,
"updated" timestamp with time zone NOT NULL,
"profile_id" integer
);
CREATE TABLE "post" (
"id" serial NOT NULL PRIMARY KEY,
"user_id" integer NOT NULL,
"title" varchar(60) NOT NULL,
"content" text NOT NULL,
"created" timestamp with time zone NOT NULL,
"updated" timestamp with time zone NOT NULL
);
CREATE TABLE "tag" (
"id" serial NOT NULL PRIMARY KEY,
"name" varchar(30) NOT NULL
);
CREATE TABLE "post_tags" (
"id" serial NOT NULL PRIMARY KEY,
"post_id" integer NOT NULL,
"tag_id" integer NOT NULL,
UNIQUE ("post_id", "tag_id")
);
CREATE TABLE "comment" (
"id" serial NOT NULL PRIMARY KEY,
"post_id" integer NOT NULL,
"content" text NOT NULL,
"parent_id" integer,
"created" timestamp with time zone NOT NULL
);
CREATE TABLE "data" (
"id" serial NOT NULL PRIMARY KEY,
"boolean" bool NOT NULL,
"char" varchar(50) NOT NULL,
"text" text NOT NULL,
"date" date NOT NULL,
"date_time" timestamp with time zone NOT NULL,
"byte" smallint CHECK("byte" >= 0 AND "byte" <= 255) NOT NULL,
"rune" integer NOT NULL,
"int" integer NOT NULL,
"int8" smallint CHECK("int8" >= -127 AND "int8" <= 128) NOT NULL,
"int16" smallint NOT NULL,
"int32" integer NOT NULL,
"int64" bigint NOT NULL,
"uint" bigint CHECK("uint" >= 0) NOT NULL,
"uint8" smallint CHECK("uint8" >= 0 AND "uint8" <= 255) NOT NULL,
"uint16" integer CHECK("uint16" >= 0) NOT NULL,
"uint32" bigint CHECK("uint32" >= 0) NOT NULL,
"uint64" bigint CHECK("uint64" >= 0) NOT NULL,
"float32" double precision NOT NULL,
"float64" double precision NOT NULL,
"decimal" numeric(8, 4)
);
CREATE TABLE "data_null" (
"id" serial NOT NULL PRIMARY KEY,
"boolean" bool,
"char" varchar(50),
"text" text,
"date" date,
"date_time" timestamp with time zone,
"byte" smallint CHECK("byte" >= 0 AND "byte" <= 255),
"rune" integer,
"int" integer,
"int8" smallint CHECK("int8" >= -127 AND "int8" <= 128),
"int16" smallint,
"int32" integer,
"int64" bigint,
"uint" bigint CHECK("uint" >= 0),
"uint8" smallint CHECK("uint8" >= 0 AND "uint8" <= 255),
"uint16" integer CHECK("uint16" >= 0),
"uint32" bigint CHECK("uint32" >= 0),
"uint64" bigint CHECK("uint64" >= 0),
"float32" double precision,
"float64" double precision,
"decimal" numeric(8, 4)
);
CREATE INDEX "user_profile_id" ON "user" ("profile_id");
CREATE INDEX "post_user_id" ON "post" ("user_id");
CREATE INDEX "comment_post_id" ON "comment" ("post_id");
CREATE INDEX "comment_parent_id" ON "comment" ("parent_id");
`}
func init() { func init() {
// err := os.Setenv("TZ", "+00:00")
// fmt.Println(err)
RegisterModel(new(Data), new(DataNull))
RegisterModel(new(User))
RegisterModel(new(Profile))
RegisterModel(new(Post))
RegisterModel(new(Tag))
RegisterModel(new(Comment))
Debug, _ = StrTo(DBARGS.Debug).Bool() Debug, _ = StrTo(DBARGS.Debug).Bool()
if DBARGS.Driver == "" || DBARGS.Source == "" { if DBARGS.Driver == "" || DBARGS.Source == "" {
@ -484,29 +164,35 @@ Default DB Drivers.
sqlite3: https://github.com/mattn/go-sqlite3 sqlite3: https://github.com/mattn/go-sqlite3
postgres: https://github.com/lib/pq postgres: https://github.com/lib/pq
eg: mysql usage:
ORM_DRIVER=mysql ORM_SOURCE="root:root@/my_db?charset=utf8" go test github.com/astaxie/beego/orm
go get -u github.com/astaxie/beego/orm
go get -u github.com/go-sql-driver/mysql
go get -u github.com/mattn/go-sqlite3
go get -u github.com/lib/pq
#### MySQL
mysql -u root -e 'create database orm_test;'
export ORM_DRIVER=mysql
export ORM_SOURCE="root:@/orm_test?charset=utf8"
go test -v github.com/astaxie/beego/orm
#### Sqlite3
touch /path/to/orm_test.db
export ORM_DRIVER=sqlite3
export ORM_SOURCE=/path/to/orm_test.db
go test -v github.com/astaxie/beego/orm
#### PostgreSQL
psql -c 'create database orm_test;' -U postgres
export ORM_DRIVER=postgres
export ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable"
go test -v github.com/astaxie/beego/orm
`) `)
os.Exit(2) os.Exit(2)
} }
RegisterDataBase("default", DBARGS.Driver, DBARGS.Source, 20) RegisterDataBase("default", DBARGS.Driver, DBARGS.Source, 20)
BootStrap()
dORM = NewOrm()
queries := strings.Split(initSQLs[DBARGS.Driver], ";")
for _, query := range queries {
query = strings.TrimSpace(query)
if len(query) == 0 {
continue
}
_, err := dORM.Raw(query).Exec()
if err != nil {
fmt.Println(err)
os.Exit(2)
}
}
} }

View File

@ -52,7 +52,7 @@ func getFieldType(val reflect.Value) (ft int, err error) {
case reflect.Int64: case reflect.Int64:
ft = TypeBigIntegerField ft = TypeBigIntegerField
case reflect.Uint8: case reflect.Uint8:
ft = TypePostiveBitField ft = TypePositiveBitField
case reflect.Uint16: case reflect.Uint16:
ft = TypePositiveSmallIntegerField ft = TypePositiveSmallIntegerField
case reflect.Uint32, reflect.Uint: case reflect.Uint32, reflect.Uint:

View File

@ -189,6 +189,47 @@ func throwFailNow(t *testing.T, err error, args ...interface{}) {
} }
} }
func TestSyncDb(t *testing.T) {
RegisterModel(new(Data), new(DataNull))
RegisterModel(new(User))
RegisterModel(new(Profile))
RegisterModel(new(Post))
RegisterModel(new(Tag))
RegisterModel(new(Comment))
BootStrap()
al := dataBaseCache.getDefault()
db := al.DB
drops := getDbDropSql(al)
for _, query := range drops {
_, err := db.Exec(query)
throwFailNow(t, err, query)
}
tables := getDbCreateSql(al)
for _, query := range tables {
_, err := db.Exec(query)
throwFailNow(t, err, query)
}
modelCache.clean()
}
func TestRegisterModels(t *testing.T) {
RegisterModel(new(Data), new(DataNull))
RegisterModel(new(User))
RegisterModel(new(Profile))
RegisterModel(new(Post))
RegisterModel(new(Tag))
RegisterModel(new(Comment))
BootStrap()
dORM = NewOrm()
}
func TestModelSyntax(t *testing.T) { func TestModelSyntax(t *testing.T) {
user := &User{} user := &User{}
ind := reflect.ValueOf(user).Elem() ind := reflect.ValueOf(user).Elem()

View File

@ -132,4 +132,5 @@ type dbBaser interface {
HasReturningID(*modelInfo, *string) bool HasReturningID(*modelInfo, *string) bool
TimeFromDB(*time.Time, *time.Location) TimeFromDB(*time.Time, *time.Location)
TimeToDB(*time.Time, *time.Location) TimeToDB(*time.Time, *time.Location)
DbTypes() map[string]string
} }