github.com/astaxie/beego@v1.12.3/orm/cmd.go (about) 1 // Copyright 2014 beego Author. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package orm 16 17 import ( 18 "flag" 19 "fmt" 20 "os" 21 "strings" 22 ) 23 24 type commander interface { 25 Parse([]string) 26 Run() error 27 } 28 29 var ( 30 commands = make(map[string]commander) 31 ) 32 33 // print help. 34 func printHelp(errs ...string) { 35 content := `orm command usage: 36 37 syncdb - auto create tables 38 sqlall - print sql of create tables 39 help - print this help 40 ` 41 42 if len(errs) > 0 { 43 fmt.Println(errs[0]) 44 } 45 fmt.Println(content) 46 os.Exit(2) 47 } 48 49 // RunCommand listen for orm command and then run it if command arguments passed. 50 func RunCommand() { 51 if len(os.Args) < 2 || os.Args[1] != "orm" { 52 return 53 } 54 55 BootStrap() 56 57 args := argString(os.Args[2:]) 58 name := args.Get(0) 59 60 if name == "help" { 61 printHelp() 62 } 63 64 if cmd, ok := commands[name]; ok { 65 cmd.Parse(os.Args[3:]) 66 cmd.Run() 67 os.Exit(0) 68 } else { 69 if name == "" { 70 printHelp() 71 } else { 72 printHelp(fmt.Sprintf("unknown command %s", name)) 73 } 74 } 75 } 76 77 // sync database struct command interface. 78 type commandSyncDb struct { 79 al *alias 80 force bool 81 verbose bool 82 noInfo bool 83 rtOnError bool 84 } 85 86 // parse orm command line arguments. 87 func (d *commandSyncDb) Parse(args []string) { 88 var name string 89 90 flagSet := flag.NewFlagSet("orm command: syncdb", flag.ExitOnError) 91 flagSet.StringVar(&name, "db", "default", "DataBase alias name") 92 flagSet.BoolVar(&d.force, "force", false, "drop tables before create") 93 flagSet.BoolVar(&d.verbose, "v", false, "verbose info") 94 flagSet.Parse(args) 95 96 d.al = getDbAlias(name) 97 } 98 99 // run orm line command. 100 func (d *commandSyncDb) Run() error { 101 var drops []string 102 if d.force { 103 drops = getDbDropSQL(d.al) 104 } 105 106 db := d.al.DB 107 108 if d.force { 109 for i, mi := range modelCache.allOrdered() { 110 query := drops[i] 111 if !d.noInfo { 112 fmt.Printf("drop table `%s`\n", mi.table) 113 } 114 _, err := db.Exec(query) 115 if d.verbose { 116 fmt.Printf(" %s\n\n", query) 117 } 118 if err != nil { 119 if d.rtOnError { 120 return err 121 } 122 fmt.Printf(" %s\n", err.Error()) 123 } 124 } 125 } 126 127 sqls, indexes := getDbCreateSQL(d.al) 128 129 tables, err := d.al.DbBaser.GetTables(db) 130 if err != nil { 131 if d.rtOnError { 132 return err 133 } 134 fmt.Printf(" %s\n", err.Error()) 135 } 136 137 for i, mi := range modelCache.allOrdered() { 138 if tables[mi.table] { 139 if !d.noInfo { 140 fmt.Printf("table `%s` already exists, skip\n", mi.table) 141 } 142 143 var fields []*fieldInfo 144 columns, err := d.al.DbBaser.GetColumns(db, mi.table) 145 if err != nil { 146 if d.rtOnError { 147 return err 148 } 149 fmt.Printf(" %s\n", err.Error()) 150 } 151 152 for _, fi := range mi.fields.fieldsDB { 153 if _, ok := columns[fi.column]; !ok { 154 fields = append(fields, fi) 155 } 156 } 157 158 for _, fi := range fields { 159 query := getColumnAddQuery(d.al, fi) 160 161 if !d.noInfo { 162 fmt.Printf("add column `%s` for table `%s`\n", fi.fullName, mi.table) 163 } 164 165 _, err := db.Exec(query) 166 if d.verbose { 167 fmt.Printf(" %s\n", query) 168 } 169 if err != nil { 170 if d.rtOnError { 171 return err 172 } 173 fmt.Printf(" %s\n", err.Error()) 174 } 175 } 176 177 for _, idx := range indexes[mi.table] { 178 if !d.al.DbBaser.IndexExists(db, idx.Table, idx.Name) { 179 if !d.noInfo { 180 fmt.Printf("create index `%s` for table `%s`\n", idx.Name, idx.Table) 181 } 182 183 query := idx.SQL 184 _, err := db.Exec(query) 185 if d.verbose { 186 fmt.Printf(" %s\n", query) 187 } 188 if err != nil { 189 if d.rtOnError { 190 return err 191 } 192 fmt.Printf(" %s\n", err.Error()) 193 } 194 } 195 } 196 197 continue 198 } 199 200 if !d.noInfo { 201 fmt.Printf("create table `%s` \n", mi.table) 202 } 203 204 queries := []string{sqls[i]} 205 for _, idx := range indexes[mi.table] { 206 queries = append(queries, idx.SQL) 207 } 208 209 for _, query := range queries { 210 _, err := db.Exec(query) 211 if d.verbose { 212 query = " " + strings.Join(strings.Split(query, "\n"), "\n ") 213 fmt.Println(query) 214 } 215 if err != nil { 216 if d.rtOnError { 217 return err 218 } 219 fmt.Printf(" %s\n", err.Error()) 220 } 221 } 222 if d.verbose { 223 fmt.Println("") 224 } 225 } 226 227 return nil 228 } 229 230 // database creation commander interface implement. 231 type commandSQLAll struct { 232 al *alias 233 } 234 235 // parse orm command line arguments. 236 func (d *commandSQLAll) Parse(args []string) { 237 var name string 238 239 flagSet := flag.NewFlagSet("orm command: sqlall", flag.ExitOnError) 240 flagSet.StringVar(&name, "db", "default", "DataBase alias name") 241 flagSet.Parse(args) 242 243 d.al = getDbAlias(name) 244 } 245 246 // run orm line command. 247 func (d *commandSQLAll) Run() error { 248 sqls, indexes := getDbCreateSQL(d.al) 249 var all []string 250 for i, mi := range modelCache.allOrdered() { 251 queries := []string{sqls[i]} 252 for _, idx := range indexes[mi.table] { 253 queries = append(queries, idx.SQL) 254 } 255 sql := strings.Join(queries, "\n") 256 all = append(all, sql) 257 } 258 fmt.Println(strings.Join(all, "\n\n")) 259 260 return nil 261 } 262 263 func init() { 264 commands["syncdb"] = new(commandSyncDb) 265 commands["sqlall"] = new(commandSQLAll) 266 } 267 268 // RunSyncdb run syncdb command line. 269 // name means table's alias name. default is "default". 270 // force means run next sql if the current is error. 271 // verbose means show all info when running command or not. 272 func RunSyncdb(name string, force bool, verbose bool) error { 273 BootStrap() 274 275 al := getDbAlias(name) 276 cmd := new(commandSyncDb) 277 cmd.al = al 278 cmd.force = force 279 cmd.noInfo = !verbose 280 cmd.verbose = verbose 281 cmd.rtOnError = true 282 return cmd.Run() 283 }