c38abf35 by slene

orm support auto create db

1 parent 1fedaf21
1 package orm
2
3 import (
4 "flag"
5 "fmt"
6 "os"
7 "strings"
8 )
9
10 type commander interface {
11 Parse([]string)
12 Run()
13 }
14
15 var (
16 commands = make(map[string]commander)
17 )
18
19 func printHelp(errs ...string) {
20 content := `orm command usage:
21
22 syncdb - auto create tables
23 sqlall - print sql of create tables
24 help - print this help
25 `
26
27 if len(errs) > 0 {
28 fmt.Println(errs[0])
29 }
30 fmt.Println(content)
31 os.Exit(2)
32 }
33
34 func RunCommand() {
35 if len(os.Args) < 2 || os.Args[1] != "orm" {
36 return
37 }
38
39 BootStrap()
40
41 args := argString(os.Args[2:])
42 name := args.Get(0)
43
44 if name == "help" {
45 printHelp()
46 }
47
48 if cmd, ok := commands[name]; ok {
49 cmd.Parse(os.Args[3:])
50 cmd.Run()
51 os.Exit(0)
52 } else {
53 if name == "" {
54 printHelp()
55 } else {
56 printHelp(fmt.Sprintf("unknown command %s", name))
57 }
58 }
59 }
60
61 type commandSyncDb struct {
62 al *alias
63 force bool
64 verbose bool
65 }
66
67 func (d *commandSyncDb) Parse(args []string) {
68 var name string
69
70 flagSet := flag.NewFlagSet("orm command: syncdb", flag.ExitOnError)
71 flagSet.StringVar(&name, "db", "default", "DataBase alias name")
72 flagSet.BoolVar(&d.force, "force", false, "drop tables before create")
73 flagSet.BoolVar(&d.verbose, "v", false, "verbose info")
74 flagSet.Parse(args)
75
76 d.al = getDbAlias(name)
77 }
78
79 func (d *commandSyncDb) Run() {
80 var drops []string
81 if d.force {
82 drops = getDbDropSql(d.al)
83 }
84
85 db := d.al.DB
86
87 if d.force {
88 for i, mi := range modelCache.allOrdered() {
89 query := drops[i]
90 _, err := db.Exec(query)
91 result := ""
92 if err != nil {
93 result = err.Error()
94 }
95 fmt.Printf("drop table `%s` %s\n", mi.table, result)
96 if d.verbose {
97 fmt.Printf(" %s\n\n", query)
98 }
99 }
100 }
101
102 tables := getDbCreateSql(d.al)
103
104 for i, mi := range modelCache.allOrdered() {
105 query := tables[i]
106 _, err := db.Exec(query)
107 fmt.Printf("create table `%s` \n", mi.table)
108 if d.verbose {
109 query = " " + strings.Join(strings.Split(query, "\n"), "\n ")
110 fmt.Println(query)
111 }
112 if err != nil {
113 fmt.Printf(" %s\n", err.Error())
114 }
115 if d.verbose {
116 fmt.Println("")
117 }
118 }
119 }
120
121 type commandSqlAll struct {
122 al *alias
123 }
124
125 func (d *commandSqlAll) Parse(args []string) {
126 var name string
127
128 flagSet := flag.NewFlagSet("orm command: sqlall", flag.ExitOnError)
129 flagSet.StringVar(&name, "db", "default", "DataBase alias name")
130 flagSet.Parse(args)
131
132 d.al = getDbAlias(name)
133 }
134
135 func (d *commandSqlAll) Run() {
136 sqls := getDbCreateSql(d.al)
137 sql := strings.Join(sqls, "\n\n")
138 fmt.Println(sql)
139 }
140
141 func init() {
142 commands["syncdb"] = new(commandSyncDb)
143 commands["sqlall"] = new(commandSqlAll)
144 }
1 package orm
2
3 import (
4 "fmt"
5 "os"
6 "strings"
7 )
8
9 func getDbAlias(name string) *alias {
10 if al, ok := dataBaseCache.get(name); ok {
11 return al
12 } else {
13 fmt.Println(fmt.Sprintf("unknown DataBase alias name %s", name))
14 os.Exit(2)
15 }
16
17 return nil
18 }
19
20 func getDbDropSql(al *alias) (sqls []string) {
21 if len(modelCache.cache) == 0 {
22 fmt.Println("no Model found, need register your model")
23 os.Exit(2)
24 }
25
26 Q := al.DbBaser.TableQuote()
27
28 for _, mi := range modelCache.allOrdered() {
29 sqls = append(sqls, fmt.Sprintf(`DROP TABLE IF EXISTS %s%s%s`, Q, mi.table, Q))
30 }
31 return sqls
32 }
33
34 func getDbCreateSql(al *alias) (sqls []string) {
35 if len(modelCache.cache) == 0 {
36 fmt.Println("no Model found, need register your model")
37 os.Exit(2)
38 }
39
40 Q := al.DbBaser.TableQuote()
41 T := al.DbBaser.DbTypes()
42
43 for _, mi := range modelCache.allOrdered() {
44 sql := fmt.Sprintf("-- %s\n", strings.Repeat("-", 50))
45 sql += fmt.Sprintf("-- Table Structure for `%s`\n", mi.fullName)
46 sql += fmt.Sprintf("-- %s\n", strings.Repeat("-", 50))
47
48 sql += fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s%s%s (\n", Q, mi.table, Q)
49
50 columns := make([]string, 0, len(mi.fields.fieldsDB))
51
52 for _, fi := range mi.fields.fieldsDB {
53
54 fieldType := fi.fieldType
55 column := fmt.Sprintf(" %s%s%s ", Q, fi.column, Q)
56 col := ""
57
58 checkColumn:
59 switch fieldType {
60 case TypeBooleanField:
61 col = T["bool"]
62 case TypeCharField:
63 col = fmt.Sprintf(T["string"], fi.size)
64 case TypeTextField:
65 col = T["string-text"]
66 case TypeDateField:
67 col = T["time.Time-date"]
68 case TypeDateTimeField:
69 col = T["time.Time"]
70 case TypeBitField:
71 col = T["int8"]
72 case TypeSmallIntegerField:
73 col = T["int16"]
74 case TypeIntegerField:
75 col = T["int32"]
76 case TypeBigIntegerField:
77 if al.Driver == DR_Sqlite {
78 fieldType = TypeIntegerField
79 goto checkColumn
80 }
81 col = T["int64"]
82 case TypePositiveBitField:
83 col = T["uint8"]
84 case TypePositiveSmallIntegerField:
85 col = T["uint16"]
86 case TypePositiveIntegerField:
87 col = T["uint32"]
88 case TypePositiveBigIntegerField:
89 col = T["uint64"]
90 case TypeFloatField:
91 col = T["float64"]
92 case TypeDecimalField:
93 s := T["float64-decimal"]
94 if strings.Index(s, "%d") == -1 {
95 col = s
96 } else {
97 col = fmt.Sprintf(s, fi.digits, fi.decimals)
98 }
99 case RelForeignKey, RelOneToOne:
100 fieldType = fi.relModelInfo.fields.pk.fieldType
101 goto checkColumn
102 }
103
104 if fi.auto {
105 if al.Driver == DR_Postgres {
106 column += T["auto"]
107 } else {
108 column += col + " " + T["auto"]
109 }
110 } else if fi.pk {
111 column += col + " " + T["pk"]
112 } else {
113 column += col
114
115 if fi.null == false {
116 column += " " + "NOT NULL"
117 }
118
119 if fi.unique {
120 column += " " + "UNIQUE"
121 }
122 }
123
124 if strings.Index(column, "%COL%") != -1 {
125 column = strings.Replace(column, "%COL%", fi.column, -1)
126 }
127
128 columns = append(columns, column)
129 }
130
131 sql += strings.Join(columns, ",\n")
132 sql += "\n)"
133
134 if al.Driver == DR_MySQL {
135 sql += " ENGINE=INNODB"
136 }
137
138 sqls = append(sqls, sql)
139 }
140
141 return sqls
142 }
1 package orm
2
3 import (
4 "flag"
5 "fmt"
6 "os"
7 )
8
9 func printHelp() {
10
11 }
12
13 func getSqlAll() (sql string) {
14 for _, mi := range modelCache.allOrdered() {
15 _ = mi
16 }
17 return
18 }
19
20 func runCommand() {
21 if len(os.Args) < 2 || os.Args[1] != "orm" {
22 return
23 }
24
25 _ = flag.NewFlagSet("orm command", flag.ExitOnError)
26
27 args := argString(os.Args[2:])
28 cmd := args.Get(0)
29
30 switch cmd {
31 case "syncdb":
32 case "sqlall":
33 sql := getSqlAll()
34 fmt.Println(sql)
35 default:
36 if cmd != "" {
37 fmt.Printf("unknown command %s", cmd)
38 } else {
39 printHelp()
40 }
41
42 os.Exit(2)
43 }
44 }
...@@ -805,7 +805,7 @@ setValue: ...@@ -805,7 +805,7 @@ setValue:
805 _, err = str.Int32() 805 _, err = str.Int32()
806 case TypeBigIntegerField: 806 case TypeBigIntegerField:
807 _, err = str.Int64() 807 _, err = str.Int64()
808 case TypePostiveBitField: 808 case TypePositiveBitField:
809 _, err = str.Uint8() 809 _, err = str.Uint8()
810 case TypePositiveSmallIntegerField: 810 case TypePositiveSmallIntegerField:
811 _, err = str.Uint16() 811 _, err = str.Uint16()
...@@ -1112,3 +1112,7 @@ func (d *dbBase) TimeFromDB(t *time.Time, tz *time.Location) { ...@@ -1112,3 +1112,7 @@ func (d *dbBase) TimeFromDB(t *time.Time, tz *time.Location) {
1112 func (d *dbBase) TimeToDB(t *time.Time, tz *time.Location) { 1112 func (d *dbBase) TimeToDB(t *time.Time, tz *time.Location) {
1113 *t = t.In(tz) 1113 *t = t.In(tz)
1114 } 1114 }
1115
1116 func (d *dbBase) DbTypes() map[string]string {
1117 return nil
1118 }
......
...@@ -17,6 +17,26 @@ var mysqlOperators = map[string]string{ ...@@ -17,6 +17,26 @@ var mysqlOperators = map[string]string{
17 "iendswith": "LIKE ?", 17 "iendswith": "LIKE ?",
18 } 18 }
19 19
20 var mysqlTypes = map[string]string{
21 "auto": "AUTO_INCREMENT NOT NULL PRIMARY KEY",
22 "pk": "NOT NULL PRIMARY KEY",
23 "bool": "bool",
24 "string": "varchar(%d)",
25 "string-text": "longtext",
26 "time.Time-date": "date",
27 "time.Time": "datetime",
28 "int8": "tinyint",
29 "int16": "smallint",
30 "int32": "integer",
31 "int64": "bigint",
32 "uint8": "tinyint unsigned",
33 "uint16": "smallint unsigned",
34 "uint32": "integer unsigned",
35 "uint64": "bigint unsigned",
36 "float64": "double precision",
37 "float64-decimal": "numeric(%d, %d)",
38 }
39
20 type dbBaseMysql struct { 40 type dbBaseMysql struct {
21 dbBase 41 dbBase
22 } 42 }
...@@ -27,6 +47,10 @@ func (d *dbBaseMysql) OperatorSql(operator string) string { ...@@ -27,6 +47,10 @@ func (d *dbBaseMysql) OperatorSql(operator string) string {
27 return mysqlOperators[operator] 47 return mysqlOperators[operator]
28 } 48 }
29 49
50 func (d *dbBaseMysql) DbTypes() map[string]string {
51 return mysqlTypes
52 }
53
30 func newdbBaseMysql() dbBaser { 54 func newdbBaseMysql() dbBaser {
31 b := new(dbBaseMysql) 55 b := new(dbBaseMysql)
32 b.ins = b 56 b.ins = b
......
...@@ -20,6 +20,26 @@ var postgresOperators = map[string]string{ ...@@ -20,6 +20,26 @@ var postgresOperators = map[string]string{
20 "iendswith": "LIKE UPPER(?)", 20 "iendswith": "LIKE UPPER(?)",
21 } 21 }
22 22
23 var postgresTypes = map[string]string{
24 "auto": "serial NOT NULL PRIMARY KEY",
25 "pk": "NOT NULL PRIMARY KEY",
26 "bool": "bool",
27 "string": "varchar(%d)",
28 "string-text": "text",
29 "time.Time-date": "date",
30 "time.Time": "timestamp with time zone",
31 "int8": `smallint CHECK("%COL%" >= -127 AND "%COL%" <= 128)`,
32 "int16": "smallint",
33 "int32": "integer",
34 "int64": "bigint",
35 "uint8": `smallint CHECK("%COL%" >= 0 AND "%COL%" <= 255)`,
36 "uint16": `integer CHECK("%COL%" >= 0)`,
37 "uint32": `bigint CHECK("%COL%" >= 0)`,
38 "uint64": `bigint CHECK("%COL%" >= 0)`,
39 "float64": "double precision",
40 "float64-decimal": "numeric(%d, %d)",
41 }
42
23 type dbBasePostgres struct { 43 type dbBasePostgres struct {
24 dbBase 44 dbBase
25 } 45 }
...@@ -87,6 +107,10 @@ func (d *dbBasePostgres) HasReturningID(mi *modelInfo, query *string) (has bool) ...@@ -87,6 +107,10 @@ func (d *dbBasePostgres) HasReturningID(mi *modelInfo, query *string) (has bool)
87 return 107 return
88 } 108 }
89 109
110 func (d *dbBasePostgres) DbTypes() map[string]string {
111 return postgresTypes
112 }
113
90 func newdbBasePostgres() dbBaser { 114 func newdbBasePostgres() dbBaser {
91 b := new(dbBasePostgres) 115 b := new(dbBasePostgres)
92 b.ins = b 116 b.ins = b
......
...@@ -19,6 +19,26 @@ var sqliteOperators = map[string]string{ ...@@ -19,6 +19,26 @@ var sqliteOperators = map[string]string{
19 "iendswith": "LIKE ? ESCAPE '\\'", 19 "iendswith": "LIKE ? ESCAPE '\\'",
20 } 20 }
21 21
22 var sqliteTypes = map[string]string{
23 "auto": "NOT NULL PRIMARY KEY AUTOINCREMENT",
24 "pk": "NOT NULL PRIMARY KEY",
25 "bool": "bool",
26 "string": "varchar(%d)",
27 "string-text": "text",
28 "time.Time-date": "date",
29 "time.Time": "datetime",
30 "int8": "tinyint",
31 "int16": "smallint",
32 "int32": "integer",
33 "int64": "bigint",
34 "uint8": "tinyint unsigned",
35 "uint16": "smallint unsigned",
36 "uint32": "integer unsigned",
37 "uint64": "bigint unsigned",
38 "float64": "real",
39 "float64-decimal": "decimal",
40 }
41
22 type dbBaseSqlite struct { 42 type dbBaseSqlite struct {
23 dbBase 43 dbBase
24 } 44 }
...@@ -43,6 +63,10 @@ func (d *dbBaseSqlite) MaxLimit() uint64 { ...@@ -43,6 +63,10 @@ func (d *dbBaseSqlite) MaxLimit() uint64 {
43 return 9223372036854775807 63 return 9223372036854775807
44 } 64 }
45 65
66 func (d *dbBaseSqlite) DbTypes() map[string]string {
67 return sqliteTypes
68 }
69
46 func newdbBaseSqlite() dbBaser { 70 func newdbBaseSqlite() dbBaser {
47 b := new(dbBaseSqlite) 71 b := new(dbBaseSqlite)
48 b.ins = b 72 b.ins = b
......
...@@ -84,3 +84,10 @@ func (mc *_modelCache) set(table string, mi *modelInfo) *modelInfo { ...@@ -84,3 +84,10 @@ func (mc *_modelCache) set(table string, mi *modelInfo) *modelInfo {
84 } 84 }
85 return mii 85 return mii
86 } 86 }
87
88 func (mc *_modelCache) clean() {
89 mc.orders = make([]string, 0)
90 mc.cache = make(map[string]*modelInfo)
91 mc.cacheByFN = make(map[string]*modelInfo)
92 mc.done = false
93 }
......
...@@ -8,7 +8,7 @@ import ( ...@@ -8,7 +8,7 @@ import (
8 "strings" 8 "strings"
9 ) 9 )
10 10
11 func registerModel(model interface{}) { 11 func registerModel(model interface{}, prefix string) {
12 val := reflect.ValueOf(model) 12 val := reflect.ValueOf(model)
13 ind := reflect.Indirect(val) 13 ind := reflect.Indirect(val)
14 typ := ind.Type() 14 typ := ind.Type()
...@@ -17,20 +17,25 @@ func registerModel(model interface{}) { ...@@ -17,20 +17,25 @@ func registerModel(model interface{}) {
17 panic(fmt.Sprintf("<orm.RegisterModel> cannot use non-ptr model struct `%s`", getFullName(typ))) 17 panic(fmt.Sprintf("<orm.RegisterModel> cannot use non-ptr model struct `%s`", getFullName(typ)))
18 } 18 }
19 19
20 info := newModelInfo(val) 20 table := getTableName(val)
21
22 if prefix != "" {
23 table = prefix + table
24 }
21 25
22 name := getFullName(typ) 26 name := getFullName(typ)
23 if _, ok := modelCache.getByFN(name); ok { 27 if _, ok := modelCache.getByFN(name); ok {
24 fmt.Printf("<orm.RegisterModel> model `%s` redeclared, must be unique\n", name) 28 fmt.Printf("<orm.RegisterModel> model `%s` repeat register, must be unique\n", name)
25 os.Exit(2) 29 os.Exit(2)
26 } 30 }
27 31
28 table := getTableName(val)
29 if _, ok := modelCache.get(table); ok { 32 if _, ok := modelCache.get(table); ok {
30 fmt.Printf("<orm.RegisterModel> table name `%s` redeclared, must be unique\n", table) 33 fmt.Printf("<orm.RegisterModel> table name `%s` repeat register, must be unique\n", table)
31 os.Exit(2) 34 os.Exit(2)
32 } 35 }
33 36
37 info := newModelInfo(val)
38
34 if info.fields.pk == nil { 39 if info.fields.pk == nil {
35 outFor: 40 outFor:
36 for _, fi := range info.fields.fieldsDB { 41 for _, fi := range info.fields.fieldsDB {
...@@ -58,6 +63,7 @@ func registerModel(model interface{}) { ...@@ -58,6 +63,7 @@ func registerModel(model interface{}) {
58 info.pkg = typ.PkgPath() 63 info.pkg = typ.PkgPath()
59 info.model = model 64 info.model = model
60 info.manual = true 65 info.manual = true
66
61 modelCache.set(table, info) 67 modelCache.set(table, info)
62 } 68 }
63 69
...@@ -72,7 +78,7 @@ func bootStrap() { ...@@ -72,7 +78,7 @@ func bootStrap() {
72 ) 78 )
73 79
74 if dataBaseCache.getDefault() == nil { 80 if dataBaseCache.getDefault() == nil {
75 err = fmt.Errorf("must have one register alias named `default`") 81 err = fmt.Errorf("must have one register DataBase alias named `default`")
76 goto end 82 goto end
77 } 83 }
78 84
...@@ -97,7 +103,7 @@ func bootStrap() { ...@@ -97,7 +103,7 @@ func bootStrap() {
97 switch fi.fieldType { 103 switch fi.fieldType {
98 case RelManyToMany: 104 case RelManyToMany:
99 if fi.relThrough != "" { 105 if fi.relThrough != "" {
100 msg := fmt.Sprintf("filed `%s` wrong rel_through value `%s`", fi.fullName, fi.relThrough) 106 msg := fmt.Sprintf("field `%s` wrong rel_through value `%s`", fi.fullName, fi.relThrough)
101 if i := strings.LastIndex(fi.relThrough, "."); i != -1 && len(fi.relThrough) > (i+1) { 107 if i := strings.LastIndex(fi.relThrough, "."); i != -1 && len(fi.relThrough) > (i+1) {
102 pn := fi.relThrough[:i] 108 pn := fi.relThrough[:i]
103 mn := fi.relThrough[i+1:] 109 mn := fi.relThrough[i+1:]
...@@ -238,11 +244,22 @@ end: ...@@ -238,11 +244,22 @@ end:
238 244
239 func RegisterModel(models ...interface{}) { 245 func RegisterModel(models ...interface{}) {
240 if modelCache.done { 246 if modelCache.done {
241 panic(fmt.Errorf("RegisterModel must be run begore BootStrap")) 247 panic(fmt.Errorf("RegisterModel must be run before BootStrap"))
248 }
249
250 for _, model := range models {
251 registerModel(model, "")
252 }
253 }
254
255 // register model with a prefix
256 func RegisterModelWithPrefix(prefix string, models ...interface{}) {
257 if modelCache.done {
258 panic(fmt.Errorf("RegisterModel must be run before BootStrap"))
242 } 259 }
243 260
244 for _, model := range models { 261 for _, model := range models {
245 registerModel(model) 262 registerModel(model, prefix)
246 } 263 }
247 } 264 }
248 265
......
...@@ -31,7 +31,7 @@ const ( ...@@ -31,7 +31,7 @@ const (
31 // int64 31 // int64
32 TypeBigIntegerField 32 TypeBigIntegerField
33 // uint8 33 // uint8
34 TypePostiveBitField 34 TypePositiveBitField
35 // uint16 35 // uint16
36 TypePositiveSmallIntegerField 36 TypePositiveSmallIntegerField
37 // uint32 37 // uint32
......
...@@ -399,7 +399,7 @@ checkType: ...@@ -399,7 +399,7 @@ checkType:
399 _, err = v.Int32() 399 _, err = v.Int32()
400 case TypeBigIntegerField: 400 case TypeBigIntegerField:
401 _, err = v.Int64() 401 _, err = v.Int64()
402 case TypePostiveBitField: 402 case TypePositiveBitField:
403 _, err = v.Uint8() 403 _, err = v.Uint8()
404 case TypePositiveSmallIntegerField: 404 case TypePositiveSmallIntegerField:
405 _, err = v.Uint16() 405 _, err = v.Uint16()
......
...@@ -90,6 +90,9 @@ func newM2MModelInfo(m1, m2 *modelInfo) (info *modelInfo) { ...@@ -90,6 +90,9 @@ func newM2MModelInfo(m1, m2 *modelInfo) (info *modelInfo) {
90 fa.auto = true 90 fa.auto = true
91 fa.pk = true 91 fa.pk = true
92 fa.dbcol = true 92 fa.dbcol = true
93 fa.name = "Id"
94 fa.column = "id"
95 fa.fullName = info.fullName + "." + fa.name
93 96
94 f1.dbcol = true 97 f1.dbcol = true
95 f2.dbcol = true 98 f2.dbcol = true
......
...@@ -3,10 +3,8 @@ package orm ...@@ -3,10 +3,8 @@ package orm
3 import ( 3 import (
4 "fmt" 4 "fmt"
5 "os" 5 "os"
6 "strings"
7 "time" 6 "time"
8 7
9 // _ "github.com/bylevel/pq"
10 _ "github.com/go-sql-driver/mysql" 8 _ "github.com/go-sql-driver/mysql"
11 _ "github.com/lib/pq" 9 _ "github.com/lib/pq"
12 _ "github.com/mattn/go-sqlite3" 10 _ "github.com/mattn/go-sqlite3"
...@@ -153,325 +151,7 @@ var ( ...@@ -153,325 +151,7 @@ var (
153 151
154 var dORM Ormer 152 var dORM Ormer
155 153
156 var initSQLs = map[string]string{
157 "mysql": "DROP TABLE IF EXISTS `user_profile`;\n" +
158 "DROP TABLE IF EXISTS `user`;\n" +
159 "DROP TABLE IF EXISTS `post`;\n" +
160 "DROP TABLE IF EXISTS `tag`;\n" +
161 "DROP TABLE IF EXISTS `post_tags`;\n" +
162 "DROP TABLE IF EXISTS `comment`;\n" +
163 "DROP TABLE IF EXISTS `data`;\n" +
164 "DROP TABLE IF EXISTS `data_null`;\n" +
165 "CREATE TABLE `user_profile` (\n" +
166 " `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
167 " `age` smallint NOT NULL,\n" +
168 " `money` double precision NOT NULL\n" +
169 ") ENGINE=INNODB;\n" +
170 "CREATE TABLE `user` (\n" +
171 " `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
172 " `user_name` varchar(30) NOT NULL UNIQUE,\n" +
173 " `email` varchar(100) NOT NULL,\n" +
174 " `password` varchar(100) NOT NULL,\n" +
175 " `status` smallint NOT NULL,\n" +
176 " `is_staff` bool NOT NULL,\n" +
177 " `is_active` bool NOT NULL,\n" +
178 " `created` date NOT NULL,\n" +
179 " `updated` datetime NOT NULL,\n" +
180 " `profile_id` integer\n" +
181 ") ENGINE=INNODB;\n" +
182 "CREATE TABLE `post` (\n" +
183 " `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
184 " `user_id` integer NOT NULL,\n" +
185 " `title` varchar(60) NOT NULL,\n" +
186 " `content` longtext NOT NULL,\n" +
187 " `created` datetime NOT NULL,\n" +
188 " `updated` datetime NOT NULL\n" +
189 ") ENGINE=INNODB;\n" +
190 "CREATE TABLE `tag` (\n" +
191 " `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
192 " `name` varchar(30) NOT NULL\n" +
193 ") ENGINE=INNODB;\n" +
194 "CREATE TABLE `post_tags` (\n" +
195 " `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
196 " `post_id` integer NOT NULL,\n" +
197 " `tag_id` integer NOT NULL,\n" +
198 " UNIQUE (`post_id`, `tag_id`)\n" +
199 ") ENGINE=INNODB;\n" +
200 "CREATE TABLE `comment` (\n" +
201 " `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
202 " `post_id` integer NOT NULL,\n" +
203 " `content` longtext NOT NULL,\n" +
204 " `parent_id` integer,\n" +
205 " `created` datetime NOT NULL\n" +
206 ") ENGINE=INNODB;\n" +
207 "CREATE TABLE `data` (\n" +
208 " `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
209 " `boolean` bool NOT NULL,\n" +
210 " `char` varchar(50) NOT NULL,\n" +
211 " `text` longtext NOT NULL,\n" +
212 " `date` date NOT NULL,\n" +
213 " `date_time` datetime NOT NULL,\n" +
214 " `byte` tinyint unsigned NOT NULL,\n" +
215 " `rune` integer NOT NULL,\n" +
216 " `int` integer NOT NULL,\n" +
217 " `int8` tinyint NOT NULL,\n" +
218 " `int16` smallint NOT NULL,\n" +
219 " `int32` integer NOT NULL,\n" +
220 " `int64` bigint NOT NULL,\n" +
221 " `uint` integer unsigned NOT NULL,\n" +
222 " `uint8` tinyint unsigned NULL,\n" +
223 " `uint16` smallint unsigned NOT NULL,\n" +
224 " `uint32` integer unsigned NOT NULL,\n" +
225 " `uint64` bigint unsigned NOT NULL,\n" +
226 " `float32` double precision NOT NULL,\n" +
227 " `float64` double precision NOT NULL,\n" +
228 " `decimal` numeric(8,4) NOT NULL\n" +
229 ") ENGINE=INNODB;\n" +
230 "CREATE TABLE `data_null` (\n" +
231 " `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,\n" +
232 " `boolean` bool,\n" +
233 " `char` varchar(50),\n" +
234 " `text` longtext,\n" +
235 " `date` date,\n" +
236 " `date_time` datetime,\n" +
237 " `byte` tinyint unsigned,\n" +
238 " `rune` integer,\n" +
239 " `int` integer,\n" +
240 " `int8` tinyint,\n" +
241 " `int16` smallint,\n" +
242 " `int32` integer,\n" +
243 " `int64` bigint,\n" +
244 " `uint` integer unsigned,\n" +
245 " `uint8` tinyint unsigned,\n" +
246 " `uint16` smallint unsigned,\n" +
247 " `uint32` integer unsigned,\n" +
248 " `uint64` bigint unsigned,\n" +
249 " `float32` double precision,\n" +
250 " `float64` double precision,\n" +
251 " `decimal` numeric(8,4)\n" +
252 ") ENGINE=INNODB;\n" +
253 "CREATE INDEX `user_141c6eec` ON `user` (`profile_id`);\n" +
254 "CREATE INDEX `post_fbfc09f1` ON `post` (`user_id`);\n" +
255 "CREATE INDEX `comment_699ae8ca` ON `comment` (`post_id`);\n" +
256 "CREATE INDEX `comment_63f17a16` ON `comment` (`parent_id`);",
257
258 "sqlite3": `
259 DROP TABLE IF EXISTS "user_profile";
260 DROP TABLE IF EXISTS "user";
261 DROP TABLE IF EXISTS "post";
262 DROP TABLE IF EXISTS "tag";
263 DROP TABLE IF EXISTS "post_tags";
264 DROP TABLE IF EXISTS "comment";
265 DROP TABLE IF EXISTS "data";
266 DROP TABLE IF EXISTS "data_null";
267 CREATE TABLE "user_profile" (
268 "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
269 "age" smallint NOT NULL,
270 "money" real NOT NULL
271 );
272 CREATE TABLE "user" (
273 "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
274 "user_name" varchar(30) NOT NULL UNIQUE,
275 "email" varchar(100) NOT NULL,
276 "password" varchar(100) NOT NULL,
277 "status" smallint NOT NULL,
278 "is_staff" bool NOT NULL,
279 "is_active" bool NOT NULL,
280 "created" date NOT NULL,
281 "updated" datetime NOT NULL,
282 "profile_id" integer
283 );
284 CREATE TABLE "post" (
285 "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
286 "user_id" integer NOT NULL,
287 "title" varchar(60) NOT NULL,
288 "content" text NOT NULL,
289 "created" datetime NOT NULL,
290 "updated" datetime NOT NULL
291 );
292 CREATE TABLE "tag" (
293 "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
294 "name" varchar(30) NOT NULL
295 );
296 CREATE TABLE "post_tags" (
297 "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
298 "post_id" integer NOT NULL,
299 "tag_id" integer NOT NULL,
300 UNIQUE ("post_id", "tag_id")
301 );
302 CREATE TABLE "comment" (
303 "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
304 "post_id" integer NOT NULL,
305 "content" text NOT NULL,
306 "parent_id" integer,
307 "created" datetime NOT NULL
308 );
309 CREATE TABLE "data" (
310 "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
311 "boolean" bool NOT NULL,
312 "char" varchar(50) NOT NULL,
313 "text" text NOT NULL,
314 "date" date NOT NULL,
315 "date_time" datetime NOT NULL,
316 "byte" tinyint unsigned NOT NULL,
317 "rune" integer NOT NULL,
318 "int" integer NOT NULL,
319 "int8" tinyint NOT NULL,
320 "int16" smallint NOT NULL,
321 "int32" integer NOT NULL,
322 "int64" bigint NOT NULL,
323 "uint" integer unsigned NOT NULL,
324 "uint8" tinyint unsigned NOT NULL,
325 "uint16" smallint unsigned NOT NULL,
326 "uint32" integer unsigned NOT NULL,
327 "uint64" bigint unsigned NOT NULL,
328 "float32" real NOT NULL,
329 "float64" real NOT NULL,
330 "decimal" decimal
331 );
332 CREATE TABLE "data_null" (
333 "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
334 "boolean" bool,
335 "char" varchar(50),
336 "text" text,
337 "date" date,
338 "date_time" datetime,
339 "byte" tinyint unsigned,
340 "rune" integer,
341 "int" integer,
342 "int8" tinyint,
343 "int16" smallint,
344 "int32" integer,
345 "int64" bigint,
346 "uint" integer unsigned,
347 "uint8" tinyint unsigned,
348 "uint16" smallint unsigned,
349 "uint32" integer unsigned,
350 "uint64" bigint unsigned,
351 "float32" real,
352 "float64" real,
353 "decimal" decimal
354 );
355 CREATE INDEX "user_141c6eec" ON "user" ("profile_id");
356 CREATE INDEX "post_fbfc09f1" ON "post" ("user_id");
357 CREATE INDEX "comment_699ae8ca" ON "comment" ("post_id");
358 CREATE INDEX "comment_63f17a16" ON "comment" ("parent_id");
359 `,
360
361 "postgres": `
362 DROP TABLE IF EXISTS "user_profile";
363 DROP TABLE IF EXISTS "user";
364 DROP TABLE IF EXISTS "post";
365 DROP TABLE IF EXISTS "tag";
366 DROP TABLE IF EXISTS "post_tags";
367 DROP TABLE IF EXISTS "comment";
368 DROP TABLE IF EXISTS "data";
369 DROP TABLE IF EXISTS "data_null";
370 CREATE TABLE "user_profile" (
371 "id" serial NOT NULL PRIMARY KEY,
372 "age" smallint NOT NULL,
373 "money" double precision NOT NULL
374 );
375 CREATE TABLE "user" (
376 "id" serial NOT NULL PRIMARY KEY,
377 "user_name" varchar(30) NOT NULL UNIQUE,
378 "email" varchar(100) NOT NULL,
379 "password" varchar(100) NOT NULL,
380 "status" smallint NOT NULL,
381 "is_staff" boolean NOT NULL,
382 "is_active" boolean NOT NULL,
383 "created" date NOT NULL,
384 "updated" timestamp with time zone NOT NULL,
385 "profile_id" integer
386 );
387 CREATE TABLE "post" (
388 "id" serial NOT NULL PRIMARY KEY,
389 "user_id" integer NOT NULL,
390 "title" varchar(60) NOT NULL,
391 "content" text NOT NULL,
392 "created" timestamp with time zone NOT NULL,
393 "updated" timestamp with time zone NOT NULL
394 );
395 CREATE TABLE "tag" (
396 "id" serial NOT NULL PRIMARY KEY,
397 "name" varchar(30) NOT NULL
398 );
399 CREATE TABLE "post_tags" (
400 "id" serial NOT NULL PRIMARY KEY,
401 "post_id" integer NOT NULL,
402 "tag_id" integer NOT NULL,
403 UNIQUE ("post_id", "tag_id")
404 );
405 CREATE TABLE "comment" (
406 "id" serial NOT NULL PRIMARY KEY,
407 "post_id" integer NOT NULL,
408 "content" text NOT NULL,
409 "parent_id" integer,
410 "created" timestamp with time zone NOT NULL
411 );
412 CREATE TABLE "data" (
413 "id" serial NOT NULL PRIMARY KEY,
414 "boolean" bool NOT NULL,
415 "char" varchar(50) NOT NULL,
416 "text" text NOT NULL,
417 "date" date NOT NULL,
418 "date_time" timestamp with time zone NOT NULL,
419 "byte" smallint CHECK("byte" >= 0 AND "byte" <= 255) NOT NULL,
420 "rune" integer NOT NULL,
421 "int" integer NOT NULL,
422 "int8" smallint CHECK("int8" >= -127 AND "int8" <= 128) NOT NULL,
423 "int16" smallint NOT NULL,
424 "int32" integer NOT NULL,
425 "int64" bigint NOT NULL,
426 "uint" bigint CHECK("uint" >= 0) NOT NULL,
427 "uint8" smallint CHECK("uint8" >= 0 AND "uint8" <= 255) NOT NULL,
428 "uint16" integer CHECK("uint16" >= 0) NOT NULL,
429 "uint32" bigint CHECK("uint32" >= 0) NOT NULL,
430 "uint64" bigint CHECK("uint64" >= 0) NOT NULL,
431 "float32" double precision NOT NULL,
432 "float64" double precision NOT NULL,
433 "decimal" numeric(8, 4)
434 );
435 CREATE TABLE "data_null" (
436 "id" serial NOT NULL PRIMARY KEY,
437 "boolean" bool,
438 "char" varchar(50),
439 "text" text,
440 "date" date,
441 "date_time" timestamp with time zone,
442 "byte" smallint CHECK("byte" >= 0 AND "byte" <= 255),
443 "rune" integer,
444 "int" integer,
445 "int8" smallint CHECK("int8" >= -127 AND "int8" <= 128),
446 "int16" smallint,
447 "int32" integer,
448 "int64" bigint,
449 "uint" bigint CHECK("uint" >= 0),
450 "uint8" smallint CHECK("uint8" >= 0 AND "uint8" <= 255),
451 "uint16" integer CHECK("uint16" >= 0),
452 "uint32" bigint CHECK("uint32" >= 0),
453 "uint64" bigint CHECK("uint64" >= 0),
454 "float32" double precision,
455 "float64" double precision,
456 "decimal" numeric(8, 4)
457 );
458 CREATE INDEX "user_profile_id" ON "user" ("profile_id");
459 CREATE INDEX "post_user_id" ON "post" ("user_id");
460 CREATE INDEX "comment_post_id" ON "comment" ("post_id");
461 CREATE INDEX "comment_parent_id" ON "comment" ("parent_id");
462 `}
463
464 func init() { 154 func init() {
465 // err := os.Setenv("TZ", "+00:00")
466 // fmt.Println(err)
467
468 RegisterModel(new(Data), new(DataNull))
469 RegisterModel(new(User))
470 RegisterModel(new(Profile))
471 RegisterModel(new(Post))
472 RegisterModel(new(Tag))
473 RegisterModel(new(Comment))
474
475 Debug, _ = StrTo(DBARGS.Debug).Bool() 155 Debug, _ = StrTo(DBARGS.Debug).Bool()
476 156
477 if DBARGS.Driver == "" || DBARGS.Source == "" { 157 if DBARGS.Driver == "" || DBARGS.Source == "" {
...@@ -484,29 +164,35 @@ Default DB Drivers. ...@@ -484,29 +164,35 @@ Default DB Drivers.
484 sqlite3: https://github.com/mattn/go-sqlite3 164 sqlite3: https://github.com/mattn/go-sqlite3
485 postgres: https://github.com/lib/pq 165 postgres: https://github.com/lib/pq
486 166
487 eg: mysql 167 usage:
488 ORM_DRIVER=mysql ORM_SOURCE="root:root@/my_db?charset=utf8" go test github.com/astaxie/beego/orm
489 `)
490 os.Exit(2)
491 }
492 168
493 RegisterDataBase("default", DBARGS.Driver, DBARGS.Source, 20) 169 go get -u github.com/astaxie/beego/orm
170 go get -u github.com/go-sql-driver/mysql
171 go get -u github.com/mattn/go-sqlite3
172 go get -u github.com/lib/pq
494 173
495 BootStrap() 174 #### MySQL
175 mysql -u root -e 'create database orm_test;'
176 export ORM_DRIVER=mysql
177 export ORM_SOURCE="root:@/orm_test?charset=utf8"
178 go test -v github.com/astaxie/beego/orm
496 179
497 dORM = NewOrm()
498 180
499 queries := strings.Split(initSQLs[DBARGS.Driver], ";") 181 #### Sqlite3
182 touch /path/to/orm_test.db
183 export ORM_DRIVER=sqlite3
184 export ORM_SOURCE=/path/to/orm_test.db
185 go test -v github.com/astaxie/beego/orm
500 186
501 for _, query := range queries { 187
502 query = strings.TrimSpace(query) 188 #### PostgreSQL
503 if len(query) == 0 { 189 psql -c 'create database orm_test;' -U postgres
504 continue 190 export ORM_DRIVER=postgres
505 } 191 export ORM_SOURCE="user=postgres dbname=orm_test sslmode=disable"
506 _, err := dORM.Raw(query).Exec() 192 go test -v github.com/astaxie/beego/orm
507 if err != nil { 193 `)
508 fmt.Println(err) 194 os.Exit(2)
509 os.Exit(2)
510 }
511 } 195 }
196
197 RegisterDataBase("default", DBARGS.Driver, DBARGS.Source, 20)
512 } 198 }
......
...@@ -52,7 +52,7 @@ func getFieldType(val reflect.Value) (ft int, err error) { ...@@ -52,7 +52,7 @@ func getFieldType(val reflect.Value) (ft int, err error) {
52 case reflect.Int64: 52 case reflect.Int64:
53 ft = TypeBigIntegerField 53 ft = TypeBigIntegerField
54 case reflect.Uint8: 54 case reflect.Uint8:
55 ft = TypePostiveBitField 55 ft = TypePositiveBitField
56 case reflect.Uint16: 56 case reflect.Uint16:
57 ft = TypePositiveSmallIntegerField 57 ft = TypePositiveSmallIntegerField
58 case reflect.Uint32, reflect.Uint: 58 case reflect.Uint32, reflect.Uint:
......
...@@ -189,6 +189,47 @@ func throwFailNow(t *testing.T, err error, args ...interface{}) { ...@@ -189,6 +189,47 @@ func throwFailNow(t *testing.T, err error, args ...interface{}) {
189 } 189 }
190 } 190 }
191 191
192 func TestSyncDb(t *testing.T) {
193 RegisterModel(new(Data), new(DataNull))
194 RegisterModel(new(User))
195 RegisterModel(new(Profile))
196 RegisterModel(new(Post))
197 RegisterModel(new(Tag))
198 RegisterModel(new(Comment))
199
200 BootStrap()
201
202 al := dataBaseCache.getDefault()
203 db := al.DB
204
205 drops := getDbDropSql(al)
206 for _, query := range drops {
207 _, err := db.Exec(query)
208 throwFailNow(t, err, query)
209 }
210
211 tables := getDbCreateSql(al)
212 for _, query := range tables {
213 _, err := db.Exec(query)
214 throwFailNow(t, err, query)
215 }
216
217 modelCache.clean()
218 }
219
220 func TestRegisterModels(t *testing.T) {
221 RegisterModel(new(Data), new(DataNull))
222 RegisterModel(new(User))
223 RegisterModel(new(Profile))
224 RegisterModel(new(Post))
225 RegisterModel(new(Tag))
226 RegisterModel(new(Comment))
227
228 BootStrap()
229
230 dORM = NewOrm()
231 }
232
192 func TestModelSyntax(t *testing.T) { 233 func TestModelSyntax(t *testing.T) {
193 user := &User{} 234 user := &User{}
194 ind := reflect.ValueOf(user).Elem() 235 ind := reflect.ValueOf(user).Elem()
......
...@@ -132,4 +132,5 @@ type dbBaser interface { ...@@ -132,4 +132,5 @@ type dbBaser interface {
132 HasReturningID(*modelInfo, *string) bool 132 HasReturningID(*modelInfo, *string) bool
133 TimeFromDB(*time.Time, *time.Location) 133 TimeFromDB(*time.Time, *time.Location)
134 TimeToDB(*time.Time, *time.Location) 134 TimeToDB(*time.Time, *time.Location)
135 DbTypes() map[string]string
135 } 136 }
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!