195e8d16e8
* Added bunch of new command names and descriptions. * Changed "all" command to "boil", so we can use "all" for the name of the all database select helper.
225 lines
7.1 KiB
Go
225 lines
7.1 KiB
Go
package cmds
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
"text/template"
|
|
|
|
"github.com/pobri19/sqlboiler/dbdrivers"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
// cmdData is used globally by all commands to access the table schema data,
|
|
// the database driver and the output file. cmdData is initialized by
|
|
// the root SQLBoiler cobra command at run time, before other commands execute.
|
|
var cmdData *CmdData
|
|
|
|
// templates holds a slice of pointers to all templates in the templates directory.
|
|
var templates []*template.Template
|
|
|
|
// SQLBoiler is the root app command
|
|
var SQLBoiler = &cobra.Command{
|
|
Use: "sqlboiler",
|
|
Short: "SQL Boiler generates boilerplate structs and statements",
|
|
Long: "SQL Boiler generates boilerplate structs and statements.\n" +
|
|
`Complete documentation is available at http://github.com/pobri19/sqlboiler`,
|
|
}
|
|
|
|
// init initializes the sqlboiler flags, such as driver, table, and output file.
|
|
// It also sets the global preRun hook and postRun hook. Every command will execute
|
|
// these hooks before and after running to initialize the shared state.
|
|
func init() {
|
|
SQLBoiler.PersistentFlags().StringP("driver", "d", "", "The name of the driver in your config.toml (mandatory)")
|
|
SQLBoiler.PersistentFlags().StringP("table", "t", "", "A comma seperated list of table names")
|
|
SQLBoiler.PersistentFlags().StringP("out", "o", "", "The name of the output file")
|
|
SQLBoiler.PersistentPreRun = sqlBoilerPreRun
|
|
SQLBoiler.PersistentPostRun = sqlBoilerPostRun
|
|
|
|
// Initialize the SQLBoiler commands and hook the custom Run functions
|
|
initCommands(SQLBoiler, sqlBoilerCommands, sqlBoilerCommandRuns)
|
|
}
|
|
|
|
// sqlBoilerPostRun cleans up the output file and database connection once
|
|
// all commands are finished running.
|
|
func sqlBoilerPostRun(cmd *cobra.Command, args []string) {
|
|
cmdData.OutFile.Close()
|
|
cmdData.DBDriver.Close()
|
|
}
|
|
|
|
// sqlBoilerPreRun executes before all commands start running. Its job is to
|
|
// initialize the shared state object (cmdData). Initialization tasks include
|
|
// assigning the database driver based off the driver flag and opening the database connection,
|
|
// retrieving a list of all the tables in the database (if specific tables are not provided
|
|
// via a flag), building the table schema for use in the templates, and opening the output file
|
|
// handle if one is specified with a flag.
|
|
func sqlBoilerPreRun(cmd *cobra.Command, args []string) {
|
|
var err error
|
|
cmdData = &CmdData{}
|
|
|
|
// Initialize the cmdData.DBDriver
|
|
initDBDriver()
|
|
|
|
// Connect to the driver database
|
|
if err = cmdData.DBDriver.Open(); err != nil {
|
|
errorQuit(fmt.Errorf("Unable to connect to the database: %s", err))
|
|
}
|
|
|
|
// Initialize the cmdData.TableNames
|
|
initTableNames()
|
|
|
|
// Initialize the cmdData.TablesInfo
|
|
initTablesInfo()
|
|
|
|
// Initialize the cmdData.OutFile
|
|
initOutFile()
|
|
|
|
// Initialize the templates
|
|
templates, err = initTemplates()
|
|
if err != nil {
|
|
errorQuit(fmt.Errorf("Unable to initialize templates: %s", err))
|
|
}
|
|
}
|
|
|
|
// initDBDriver attempts to set the cmdData DBDriver based off the passed in
|
|
// driver flag value. If an invalid flag string is provided the program will exit.
|
|
func initDBDriver() {
|
|
// Retrieve driver flag
|
|
driverName := SQLBoiler.PersistentFlags().Lookup("driver").Value.String()
|
|
if driverName == "" {
|
|
errorQuit(errors.New("Must supply a driver flag."))
|
|
}
|
|
|
|
// Create a driver based off driver flag
|
|
switch driverName {
|
|
case "postgres":
|
|
cmdData.DBDriver = dbdrivers.NewPostgresDriver(
|
|
cfg.Postgres.User,
|
|
cfg.Postgres.Pass,
|
|
cfg.Postgres.DBName,
|
|
cfg.Postgres.Host,
|
|
cfg.Postgres.Port,
|
|
)
|
|
}
|
|
|
|
if cmdData.DBDriver == nil {
|
|
errorQuit(errors.New("An invalid driver name was provided"))
|
|
}
|
|
}
|
|
|
|
// initTableNames will create a string slice out of the passed in table flag value
|
|
// if one is provided. If no flag is provided, it will attempt to connect to the
|
|
// database to retrieve all "public" table names, and build a slice out of that result.
|
|
func initTableNames() {
|
|
// Retrieve the list of tables
|
|
tn := SQLBoiler.PersistentFlags().Lookup("table").Value.String()
|
|
|
|
if len(tn) != 0 {
|
|
cmdData.TableNames = strings.Split(tn, ",")
|
|
for i, name := range cmdData.TableNames {
|
|
cmdData.TableNames[i] = strings.TrimSpace(name)
|
|
}
|
|
}
|
|
|
|
// If no table names are provided attempt to process all tables in database
|
|
if len(cmdData.TableNames) == 0 {
|
|
// get all table names
|
|
var err error
|
|
cmdData.TableNames, err = cmdData.DBDriver.GetAllTableNames()
|
|
if err != nil {
|
|
errorQuit(fmt.Errorf("Unable to get all table names: %s", err))
|
|
}
|
|
|
|
if len(cmdData.TableNames) == 0 {
|
|
errorQuit(errors.New("No tables found in database, migrate some tables first"))
|
|
}
|
|
}
|
|
}
|
|
|
|
// initTablesInfo builds a description of each table (column name, column type)
|
|
// and assigns it to cmdData.TablesInfo, the slice of dbdrivers.DBTable slices.
|
|
func initTablesInfo() {
|
|
// loop over table Names and build TablesInfo
|
|
for i := 0; i < len(cmdData.TableNames); i++ {
|
|
tInfo, err := cmdData.DBDriver.GetTableInfo(cmdData.TableNames[i])
|
|
if err != nil {
|
|
errorQuit(fmt.Errorf("Unable to get the table info: %s", err))
|
|
}
|
|
|
|
cmdData.TablesInfo = append(cmdData.TablesInfo, tInfo)
|
|
}
|
|
}
|
|
|
|
// initOutFile opens a file handle to the file name specified by the out flag.
|
|
// If no file name is provided, out will remain nil and future output will be
|
|
// piped to Stdout instead of to a file.
|
|
func initOutFile() {
|
|
// open the out file filehandle
|
|
outf := SQLBoiler.PersistentFlags().Lookup("out").Value.String()
|
|
if outf != "" {
|
|
var err error
|
|
cmdData.OutFile, err = os.Create(outf)
|
|
if err != nil {
|
|
errorQuit(fmt.Errorf("Unable to obtain output file handle: %s", err))
|
|
}
|
|
}
|
|
}
|
|
|
|
// initTemplates loads all of the template files in the /cmds/templates directory
|
|
// and returns a slice of pointers to these templates.
|
|
func initTemplates() ([]*template.Template, error) {
|
|
wd, err := os.Getwd()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
pattern := filepath.Join(wd, "/cmds/templates", "*.tpl")
|
|
tpl, err := template.New("").Funcs(sqlBoilerTemplateFuncs).ParseGlob(pattern)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return tpl.Templates(), err
|
|
}
|
|
|
|
// initCommands loads all of the commands in the sqlBoilerCommands and hooks their run functions.
|
|
func initCommands(rootCmd *cobra.Command, commands map[string]*cobra.Command, commandRuns map[string]CobraRunFunc) {
|
|
var commandNames []string
|
|
|
|
// Build a list of command names to alphabetically sort them for ordered loading.
|
|
for _, c := range commands {
|
|
// Skip the boil command load, we do it manually below.
|
|
if c.Name() == "boil" {
|
|
continue
|
|
}
|
|
|
|
commandNames = append(commandNames, c.Name())
|
|
}
|
|
|
|
// Initialize the "boil" command first, and manually. It should be at the top of the help file.
|
|
commands["boil"].Run = commandRuns["boil"]
|
|
rootCmd.AddCommand(commands["boil"])
|
|
|
|
// Load commands alphabetically. This ensures proper order of help file.
|
|
sort.Strings(commandNames)
|
|
|
|
// Loop every command name, load it and hook it to its Run handler
|
|
for _, c := range commandNames {
|
|
// If there is a commandRun for the command (matched by name)
|
|
// then set the Run hook
|
|
r, ok := commandRuns[c]
|
|
if ok {
|
|
commands[c].Run = r
|
|
} else {
|
|
commands[c].Run = defaultRun // Load default run if no custom run is found
|
|
}
|
|
|
|
// Add the command
|
|
rootCmd.AddCommand(commands[c])
|
|
}
|
|
}
|