From d9cd6e5e54b6f7bd2d74c385abaf01713c7c215c Mon Sep 17 00:00:00 2001 From: Leo Lou Date: Sat, 25 Nov 2017 15:50:56 +0900 Subject: [PATCH 01/10] Add support for config flag --- main.go | 36 ++++++++++++++------- templates_test/singleton/boil_main_test.tpl | 13 +++++++- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/main.go b/main.go index bc29a6c8e..839c6c97f 100644 --- a/main.go +++ b/main.go @@ -17,22 +17,22 @@ import ( const sqlBoilerVersion = "2.6.0" var ( - cmdState *boilingcore.State - cmdConfig *boilingcore.Config + flagConfigFile string + cmdState *boilingcore.State + cmdConfig *boilingcore.Config ) -func main() { - var err error - - // Too much happens between here and cobra's argument handling, for - // something so simple just do it immediately. - for _, arg := range os.Args { - if arg == "--version" { - fmt.Println("SQLBoiler v" + sqlBoilerVersion) - return +func initConfig() { + if len(flagConfigFile) == 0 { + viper.SetConfigFile(flagConfigFile) + if err := viper.ReadInConfig(); err != nil { + fmt.Println("Can't read config:", err) + os.Exit(1) } + return } + var err error viper.SetConfigName("sqlboiler") configHome := os.Getenv("XDG_CONFIG_HOME") @@ -56,6 +56,17 @@ func main() { // Ignore errors here, fallback to other validation methods. // Users can use environment variables if a config is not found. _ = viper.ReadInConfig() +} + +func main() { + // Too much happens between here and cobra's argument handling, for + // something so simple just do it immediately. + for _, arg := range os.Args { + if arg == "--version" { + fmt.Println("SQLBoiler v" + sqlBoilerVersion) + return + } + } // Set up the cobra root command var rootCmd = &cobra.Command{ @@ -71,7 +82,10 @@ func main() { SilenceUsage: true, } + cobra.OnInitialize(initConfig) + // Set up the cobra root command flags + rootCmd.PersistentFlags().StringVar(&flagConfigFile, "config", "Supply the name of the config file to override the default lookup", "config file") rootCmd.PersistentFlags().StringP("output", "o", "models", "The name of the folder to output to") rootCmd.PersistentFlags().StringP("schema", "s", "", "schema name for drivers that support it (default psql: public, mssql: dbo)") rootCmd.PersistentFlags().StringP("pkgname", "p", "models", "The name you wish to assign to your generated package") diff --git a/templates_test/singleton/boil_main_test.tpl b/templates_test/singleton/boil_main_test.tpl index ebb4758a1..805fe40eb 100644 --- a/templates_test/singleton/boil_main_test.tpl +++ b/templates_test/singleton/boil_main_test.tpl @@ -1,4 +1,5 @@ var flagDebugMode = flag.Bool("test.sqldebug", false, "Turns on debug mode for SQL statements") +var flagConfigFile = flag.String("test.config", "", "Overrides the default config") var ( dbMain tester @@ -17,6 +18,9 @@ func TestMain(m *testing.M) { } rand.Seed(time.Now().UnixNano()) + + flag.Parse() + var err error // Load configuration @@ -33,7 +37,6 @@ func TestMain(m *testing.M) { } // Set DebugMode so we can see generated sql statements - flag.Parse() boil.DebugMode = *flagDebugMode if err = dbMain.setup(); err != nil { @@ -59,6 +62,14 @@ func TestMain(m *testing.M) { } func initViper() error { + if flagConfigFile != nil && *flagConfigFile != "" { + viper.SetConfigFile(*flagConfigFile) + if err := viper.ReadInConfig(); err != nil { + return err + } + return nil + } + var err error viper.SetConfigName("sqlboiler") From 9301ec147147f5591968a598eed6bdd442ce9252 Mon Sep 17 00:00:00 2001 From: Mariusz Obajtek Date: Wed, 4 Apr 2018 09:15:51 +0200 Subject: [PATCH 02/10] Ignore MySQL virtual columns --- bdb/drivers/mysql.go | 10 ++++++++-- main.go | 4 ++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go index d5aaab6af..a59ad8acf 100644 --- a/bdb/drivers/mysql.go +++ b/bdb/drivers/mysql.go @@ -17,6 +17,12 @@ import ( // then tinyint(1) will be mapped in your generated structs to bool opposed to int8. var TinyintAsBool bool +// IgnoreVirtualColumns is a global that is set from main.go if a user specifies +// this flag when generating. This flag only applies to MySQL so we're using a global +// instead, to avoid breaking the interface. If IgnoreVirtualColumns is true then +// virtual columns present in the schema will be ignored during the code generation +var IgnoreVirtualColumns bool + // MySQLDriver holds the database connection string and a handle // to the database connection. type MySQLDriver struct { @@ -148,8 +154,8 @@ func (m *MySQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) { (select count(*) from information_schema.key_column_usage where table_schema = kcu.table_schema and table_name = tc.table_name and constraint_name = tc.constraint_name) = 1 ) as is_unique from information_schema.columns as c - where table_name = ? and table_schema = ?; - `, tableName, schema) + where table_name = ? and table_schema = ? and (? or c.extra != 'VIRTUAL GENERATED'); + `, tableName, schema, IgnoreVirtualColumns) if err != nil { return nil, err diff --git a/main.go b/main.go index bc29a6c8e..0985c8177 100644 --- a/main.go +++ b/main.go @@ -86,6 +86,7 @@ func main() { rootCmd.PersistentFlags().BoolP("no-auto-timestamps", "", false, "Disable automatic timestamps for created_at/updated_at") rootCmd.PersistentFlags().BoolP("version", "", false, "Print the version") rootCmd.PersistentFlags().BoolP("tinyint-as-bool", "", false, "Map MySQL tinyint(1) in Go to bool instead of int8") + rootCmd.PersistentFlags().BoolP("ignore-virtual-columns", "", false, "Ignore generating models and boilerplate code for MySQL virtual columns") rootCmd.PersistentFlags().BoolP("wipe", "", false, "Delete the output folder (rm -rf) before generation to ensure sanity") rootCmd.PersistentFlags().StringP("struct-tag-casing", "", "snake", "Decides the casing for go structure tag names. camel or snake (default snake)") @@ -234,6 +235,9 @@ func preRun(cmd *cobra.Command, args []string) error { // Set MySQL TinyintAsBool global var. This flag only applies to MySQL. drivers.TinyintAsBool = viper.GetBool("tinyint-as-bool") + // Set MySQL IgnoreVirtualColumns global var. This flag only applies to MySQL. + drivers.IgnoreVirtualColumns = viper.GetBool("ignore-virtual-columns") + // MySQL doesn't have schemas, just databases cmdConfig.Schema = cmdConfig.MySQL.DBName From e98388428bcbb37b6716b642a8b8b62d4c7d8c34 Mon Sep 17 00:00:00 2001 From: Mariusz Obajtek Date: Wed, 4 Apr 2018 09:40:23 +0200 Subject: [PATCH 03/10] Fix condition --- bdb/drivers/mysql.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go index a59ad8acf..9f1b40eb1 100644 --- a/bdb/drivers/mysql.go +++ b/bdb/drivers/mysql.go @@ -154,7 +154,7 @@ func (m *MySQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) { (select count(*) from information_schema.key_column_usage where table_schema = kcu.table_schema and table_name = tc.table_name and constraint_name = tc.constraint_name) = 1 ) as is_unique from information_schema.columns as c - where table_name = ? and table_schema = ? and (? or c.extra != 'VIRTUAL GENERATED'); + where table_name = ? and table_schema = ? and (c.extra != 'VIRTUAL GENERATED' or not ?); `, tableName, schema, IgnoreVirtualColumns) if err != nil { From f405f0beaedf627b63b6b6518e9e060b03615ce5 Mon Sep 17 00:00:00 2001 From: Daniel Upton Date: Fri, 6 Apr 2018 14:52:57 +0000 Subject: [PATCH 04/10] Support PostgreSQL citext fields Postgres has a [citext type](https://www.postgresql.org/docs/9.1/static/citext.html) for storing textual data that you often want to perform case-insensitive operations on (e.g. usernames). It can be treated as a normal string. --- bdb/drivers/postgres.go | 14 ++++++++++---- testdata/postgres_test_schema.sql | 6 +++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/bdb/drivers/postgres.go b/bdb/drivers/postgres.go index d08d93f6b..611eefcf3 100644 --- a/bdb/drivers/postgres.go +++ b/bdb/drivers/postgres.go @@ -348,10 +348,13 @@ func (p *PostgresDriver) TranslateColumnType(c bdb.Column) bdb.Column { // Make DBType something like ARRAYinteger for parsing with randomize.Struct c.DBType = c.DBType + *c.ArrType case "USER-DEFINED": - if c.UDTName == "hstore" { + switch c.UDTName { + case "hstore": c.Type = "types.HStore" c.DBType = "hstore" - } else { + case "citext": + c.Type = "null.String" + default: c.Type = "string" fmt.Fprintf(os.Stderr, "Warning: Incompatible data type detected: %s\n", c.UDTName) } @@ -387,10 +390,13 @@ func (p *PostgresDriver) TranslateColumnType(c bdb.Column) bdb.Column { // Make DBType something like ARRAYinteger for parsing with randomize.Struct c.DBType = c.DBType + *c.ArrType case "USER-DEFINED": - if c.UDTName == "hstore" { + switch c.UDTName { + case "hstore": c.Type = "types.HStore" c.DBType = "hstore" - } else { + case "citext": + c.Type = "string" + default: c.Type = "string" fmt.Printf("Warning: Incompatible data type detected: %s\n", c.UDTName) } diff --git a/testdata/postgres_test_schema.sql b/testdata/postgres_test_schema.sql index 3e29c7433..350ffb1b2 100644 --- a/testdata/postgres_test_schema.sql +++ b/testdata/postgres_test_schema.sql @@ -1,3 +1,5 @@ +CREATE EXTENSION IF NOT EXISTS citext; + CREATE TYPE workday AS ENUM('monday', 'tuesday', 'wednesday', 'thursday', 'friday'); CREATE TYPE faceyface AS ENUM('angry', 'hungry', 'bitter'); @@ -179,7 +181,9 @@ CREATE TABLE magic ( iii txid_snapshot NULL, jjj txid_snapshot NOT NULL, kkk xml NULL, - lll xml NOT NULL + lll xml NOT NULL, + mmm citext NULL, + nnn citext NOT NULL ); create table owner ( From 52e31013f323ee3a4d02fb19fc229ca767314bd4 Mon Sep 17 00:00:00 2001 From: Nykakin Date: Mon, 9 Apr 2018 23:04:16 +0200 Subject: [PATCH 05/10] Revert previous changes --- bdb/drivers/mysql.go | 10 ++-------- main.go | 4 ---- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go index 9f1b40eb1..d5aaab6af 100644 --- a/bdb/drivers/mysql.go +++ b/bdb/drivers/mysql.go @@ -17,12 +17,6 @@ import ( // then tinyint(1) will be mapped in your generated structs to bool opposed to int8. var TinyintAsBool bool -// IgnoreVirtualColumns is a global that is set from main.go if a user specifies -// this flag when generating. This flag only applies to MySQL so we're using a global -// instead, to avoid breaking the interface. If IgnoreVirtualColumns is true then -// virtual columns present in the schema will be ignored during the code generation -var IgnoreVirtualColumns bool - // MySQLDriver holds the database connection string and a handle // to the database connection. type MySQLDriver struct { @@ -154,8 +148,8 @@ func (m *MySQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) { (select count(*) from information_schema.key_column_usage where table_schema = kcu.table_schema and table_name = tc.table_name and constraint_name = tc.constraint_name) = 1 ) as is_unique from information_schema.columns as c - where table_name = ? and table_schema = ? and (c.extra != 'VIRTUAL GENERATED' or not ?); - `, tableName, schema, IgnoreVirtualColumns) + where table_name = ? and table_schema = ?; + `, tableName, schema) if err != nil { return nil, err diff --git a/main.go b/main.go index 0985c8177..bc29a6c8e 100644 --- a/main.go +++ b/main.go @@ -86,7 +86,6 @@ func main() { rootCmd.PersistentFlags().BoolP("no-auto-timestamps", "", false, "Disable automatic timestamps for created_at/updated_at") rootCmd.PersistentFlags().BoolP("version", "", false, "Print the version") rootCmd.PersistentFlags().BoolP("tinyint-as-bool", "", false, "Map MySQL tinyint(1) in Go to bool instead of int8") - rootCmd.PersistentFlags().BoolP("ignore-virtual-columns", "", false, "Ignore generating models and boilerplate code for MySQL virtual columns") rootCmd.PersistentFlags().BoolP("wipe", "", false, "Delete the output folder (rm -rf) before generation to ensure sanity") rootCmd.PersistentFlags().StringP("struct-tag-casing", "", "snake", "Decides the casing for go structure tag names. camel or snake (default snake)") @@ -235,9 +234,6 @@ func preRun(cmd *cobra.Command, args []string) error { // Set MySQL TinyintAsBool global var. This flag only applies to MySQL. drivers.TinyintAsBool = viper.GetBool("tinyint-as-bool") - // Set MySQL IgnoreVirtualColumns global var. This flag only applies to MySQL. - drivers.IgnoreVirtualColumns = viper.GetBool("ignore-virtual-columns") - // MySQL doesn't have schemas, just databases cmdConfig.Schema = cmdConfig.MySQL.DBName From 551576ad77a91b00b86793c767dfdb0ddac2073b Mon Sep 17 00:00:00 2001 From: Nykakin Date: Mon, 9 Apr 2018 23:08:38 +0200 Subject: [PATCH 06/10] Ignore virtual columns by default https://github.com/volatiletech/sqlboiler/pull/266 --- bdb/drivers/mysql.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go index d5aaab6af..1a3d55e54 100644 --- a/bdb/drivers/mysql.go +++ b/bdb/drivers/mysql.go @@ -148,7 +148,7 @@ func (m *MySQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) { (select count(*) from information_schema.key_column_usage where table_schema = kcu.table_schema and table_name = tc.table_name and constraint_name = tc.constraint_name) = 1 ) as is_unique from information_schema.columns as c - where table_name = ? and table_schema = ?; + where table_name = ? and table_schema = ? and c.extra not like '%VIRTUAL%'; `, tableName, schema) if err != nil { From 64255cae61d6b8982bbdca0e42237cf30a827b38 Mon Sep 17 00:00:00 2001 From: Aaron L Date: Sun, 13 May 2018 08:28:36 -0700 Subject: [PATCH 07/10] Install locales in dockerfile - Install locales to fix build issue - Upgrade go version to less insecure one Change originally PR'd in #278 by bannzai --- testdata/Dockerfile | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/testdata/Dockerfile b/testdata/Dockerfile index 034cedce7..05d3029f5 100644 --- a/testdata/Dockerfile +++ b/testdata/Dockerfile @@ -2,19 +2,19 @@ FROM ubuntu:16.04 ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/opt/mssql-tools/bin -ENV GODIST go1.8.linux-amd64.tar.gz - -# Set up locales for sqlcmd (otherwise it breaks) -RUN locale-gen en_US.UTF-8 \ - && echo "LC_ALL=en_US.UTF-8" >> /etc/default/locale \ - && echo "LANG=en_US.UTF-8" >> /etc/default/locale +ENV GODIST go1.10.2.linux-amd64.tar.gz # Install bootstrap-y tools RUN apt-get update \ && apt-get install -y apt-transport-https software-properties-common python3-software-properties \ && apt-add-repository ppa:git-core/ppa \ && apt-get update \ - && apt-get install -y curl git + && apt-get install -y curl git locales + +# Set up locales for sqlcmd (otherwise it breaks) +RUN locale-gen en_US.UTF-8 \ + && echo "LC_ALL=en_US.UTF-8" >> /etc/default/locale \ + && echo "LANG=en_US.UTF-8" >> /etc/default/locale # Install database clients # MySQL 8.0 is still in development, so we're using 5.7 which is already From 331a9f685f3f21ca6e22ad29eae7291056711b04 Mon Sep 17 00:00:00 2001 From: Aaron L Date: Wed, 23 May 2018 16:52:07 -0700 Subject: [PATCH 08/10] Fix a bad printf verb. - Go vet is now run on tests automatically in Go 1.10 and this caused a test failure. --- strmangle/strmangle_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/strmangle/strmangle_test.go b/strmangle/strmangle_test.go index 0d67cd5b7..b1d07743d 100644 --- a/strmangle/strmangle_test.go +++ b/strmangle/strmangle_test.go @@ -596,9 +596,9 @@ func TestReplaceReservedWords(t *testing.T) { for i, test := range tests { got := ReplaceReservedWords(test.Word) if test.Replace && !strings.HasSuffix(got, "_") { - t.Errorf("%i) want suffixed (%s), got: %s", i, test.Word, got) + t.Errorf("%d) want suffixed (%s), got: %s", i, test.Word, got) } else if !test.Replace && strings.HasSuffix(got, "_") { - t.Errorf("%i) want normal (%s), got: %s", i, test.Word, got) + t.Errorf("%d) want normal (%s), got: %s", i, test.Word, got) } } } From 3cd72d748076abf601e753d432ef5f3564977698 Mon Sep 17 00:00:00 2001 From: Aaron L Date: Wed, 23 May 2018 17:06:35 -0700 Subject: [PATCH 09/10] Fix the config code The original code that was submitted had several bugs. 1. The default value for the config flag was a usage sentence. 2. The length check was inverted so the code to load the sentence would never execute since the default was a sentence. --- main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 839c6c97f..9af02ff79 100644 --- a/main.go +++ b/main.go @@ -23,7 +23,7 @@ var ( ) func initConfig() { - if len(flagConfigFile) == 0 { + if len(flagConfigFile) != 0 { viper.SetConfigFile(flagConfigFile) if err := viper.ReadInConfig(); err != nil { fmt.Println("Can't read config:", err) @@ -85,7 +85,7 @@ func main() { cobra.OnInitialize(initConfig) // Set up the cobra root command flags - rootCmd.PersistentFlags().StringVar(&flagConfigFile, "config", "Supply the name of the config file to override the default lookup", "config file") + rootCmd.PersistentFlags().StringVarP(&flagConfigFile, "config", "c", "", "Supply the name of the config file to override the default lookup") rootCmd.PersistentFlags().StringP("output", "o", "models", "The name of the folder to output to") rootCmd.PersistentFlags().StringP("schema", "s", "", "schema name for drivers that support it (default psql: public, mssql: dbo)") rootCmd.PersistentFlags().StringP("pkgname", "p", "models", "The name you wish to assign to your generated package") From d542ceabddd9b77faba337c696a9278cf43056b7 Mon Sep 17 00:00:00 2001 From: Aaron L Date: Wed, 23 May 2018 17:08:35 -0700 Subject: [PATCH 10/10] Bump version --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 9af02ff79..68f2c6048 100644 --- a/main.go +++ b/main.go @@ -14,7 +14,7 @@ import ( "github.com/volatiletech/sqlboiler/boilingcore" ) -const sqlBoilerVersion = "2.6.0" +const sqlBoilerVersion = "2.7.0" var ( flagConfigFile string