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  }