From 72c68e22de662813f01140860de62dd18550169d Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Mon, 19 Dec 2016 19:29:11 -0800
Subject: [PATCH 001/179] Fix exists

- Add tests for exists
---
 templates_test/finishers.tpl                  | 46 ++++++++++++++++++-
 templates_test/singleton/boil_suites_test.tpl | 10 ++++
 2 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/templates_test/finishers.tpl b/templates_test/finishers.tpl
index fa8b129..b3ba672 100644
--- a/templates_test/finishers.tpl
+++ b/templates_test/finishers.tpl
@@ -95,6 +95,15 @@ func test{{$tableNamePlural}}Count(t *testing.T) {
 
 	tx := MustTx(boil.Begin())
 	defer tx.Rollback()
+	count, err := {{$tableNamePlural}}(tx).Count()
+	if err != nil {
+		t.Error(err)
+	}
+
+	if count != 0 {
+		t.Error("want 0 records found")
+	}
+
 	if err = {{$varNameSingular}}One.Insert(tx); err != nil {
 		t.Error(err)
 	}
@@ -102,7 +111,7 @@ func test{{$tableNamePlural}}Count(t *testing.T) {
 		t.Error(err)
 	}
 
-	count, err := {{$tableNamePlural}}(tx).Count()
+	count, err = {{$tableNamePlural}}(tx).Count()
 	if err != nil {
 		t.Error(err)
 	}
@@ -111,3 +120,38 @@ func test{{$tableNamePlural}}Count(t *testing.T) {
 		t.Error("want 2 records, got:", count)
 	}
 }
+
+func test{{$tableNamePlural}}ExistsFinisher(t *testing.T) {
+	t.Parallel()
+
+	var err error
+	seed := randomize.NewSeed()
+	{{$varNameSingular}}One := &{{$tableNameSingular}}{}
+	if err = randomize.Struct(seed, {{$varNameSingular}}One, {{$varNameSingular}}DBTypes, false, {{$varNameSingular}}ColumnsWithDefault...); err != nil {
+		t.Errorf("Unable to randomize {{$tableNameSingular}} struct: %s", err)
+	}
+
+	tx := MustTx(boil.Begin())
+	defer tx.Rollback()
+	exists, err := {{$tableNamePlural}}(tx).Exists()
+	if err != nil {
+		t.Error(err)
+	}
+
+	if exists {
+		t.Error("the record should not exist")
+	}
+
+	if err = {{$varNameSingular}}One.Insert(tx); err != nil {
+		t.Error(err)
+	}
+
+	exists, err = {{$tableNamePlural}}(tx).Exists()
+	if err != nil {
+		t.Error(err)
+	}
+
+	if !exists {
+		t.Error("wanted record to exist")
+	}
+}
diff --git a/templates_test/singleton/boil_suites_test.tpl b/templates_test/singleton/boil_suites_test.tpl
index 8723da4..bf105a3 100644
--- a/templates_test/singleton/boil_suites_test.tpl
+++ b/templates_test/singleton/boil_suites_test.tpl
@@ -105,6 +105,16 @@ func TestCount(t *testing.T) {
   {{- end -}}
 }
 
+func TestExistsFinisher(t *testing.T) {
+  {{- range $index, $table := .Tables}}
+  {{- if $table.IsJoinTable -}}
+  {{- else -}}
+  {{- $tableName := $table.Name | plural | titleCase -}}
+  t.Run("{{$tableName}}", test{{$tableName}}ExistsFinisher)
+  {{end -}}
+  {{- end -}}
+}
+
 {{if not .NoHooks -}}
 func TestHooks(t *testing.T) {
   {{- range $index, $table := .Tables}}

From 94a6604d195bb3c52d926cece8af27b33a3fcbd7 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Wed, 28 Dec 2016 14:47:57 +1000
Subject: [PATCH 002/179] Fix missing string array import

---
 imports.go | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/imports.go b/imports.go
index 880ba77..f545a28 100644
--- a/imports.go
+++ b/imports.go
@@ -342,6 +342,9 @@ var importsBasedOnType = map[string]imports{
 	"types.BoolArray": {
 		thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
 	},
+	"types.StringArray": {
+		thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+	},
 	"types.Hstore": {
 		thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
 	},

From 5449ce7c6ca1fd2f49f2cf96ccb7e2d9ae698c90 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 27 Dec 2016 23:31:24 -0800
Subject: [PATCH 003/179] Bump to 2.1.3

---
 main.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/main.go b/main.go
index cf68812..b836181 100644
--- a/main.go
+++ b/main.go
@@ -12,7 +12,7 @@ import (
 	"github.com/spf13/viper"
 )
 
-const sqlBoilerVersion = "2.1.1"
+const sqlBoilerVersion = "2.1.3"
 
 var (
 	cmdState  *State

From dea748d40945eb0a9077476931d787b3c93ea1f7 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Mon, 2 Jan 2017 15:16:08 +1000
Subject: [PATCH 004/179] Add --tinyint-as-bool flag (v2.1.4 release)

---
 bdb/column.go                  |  6 ++++++
 bdb/drivers/mysql.go           | 35 ++++++++++++++++++++++++++--------
 main.go                        |  7 ++++++-
 testdata/mysql_test_schema.sql |  4 +++-
 4 files changed, 42 insertions(+), 10 deletions(-)

diff --git a/bdb/column.go b/bdb/column.go
index b5c408e..5ed7a8b 100644
--- a/bdb/column.go
+++ b/bdb/column.go
@@ -23,6 +23,12 @@ type Column struct {
 	// https://www.postgresql.org/docs/9.1/static/infoschema-element-types.html
 	ArrType *string
 	UDTName string
+
+	// MySQL only bits
+	// Used to get full type, ex:
+	// tinyint(1) instead of tinyint
+	// Used for "tinyint-as-bool" flag
+	FullDBType string
 }
 
 // ColumnNames of the columns.
diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go
index 7f1cd4b..4e74232 100644
--- a/bdb/drivers/mysql.go
+++ b/bdb/drivers/mysql.go
@@ -11,6 +11,12 @@ import (
 	"github.com/vattle/sqlboiler/bdb"
 )
 
+// TinyintAsBool 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 TinyintAsBool is true
+// then tinyint(1) will be mapped in your generated structs to bool opposed to int8.
+var TinyintAsBool bool
+
 // MySQLDriver holds the database connection string and a handle
 // to the database connection.
 type MySQLDriver struct {
@@ -123,6 +129,7 @@ func (m *MySQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
 	rows, err := m.dbConn.Query(`
 	select
 	c.column_name,
+	c.column_type,
 	if(c.data_type = 'enum', c.column_type, c.data_type),
 	if(extra = 'auto_increment','auto_increment', c.column_default),
 	c.is_nullable = 'YES',
@@ -144,19 +151,21 @@ func (m *MySQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
 	defer rows.Close()
 
 	for rows.Next() {
-		var colName, colType string
+		var colName, colType, colFullType string
 		var nullable, unique bool
 		var defaultValue *string
-		if err := rows.Scan(&colName, &colType, &defaultValue, &nullable, &unique); err != nil {
+		if err := rows.Scan(&colName, &colFullType, &colType, &defaultValue, &nullable, &unique); err != nil {
 			return nil, errors.Wrapf(err, "unable to scan for table %s", tableName)
 		}
 
 		column := bdb.Column{
-			Name:     colName,
-			DBType:   colType,
-			Nullable: nullable,
-			Unique:   unique,
+			Name:       colName,
+			FullDBType: colFullType, // example: tinyint(1) instead of tinyint
+			DBType:     colType,
+			Nullable:   nullable,
+			Unique:     unique,
 		}
+
 		if defaultValue != nil && *defaultValue != "NULL" {
 			column.Default = *defaultValue
 		}
@@ -260,7 +269,12 @@ func (m *MySQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 	if c.Nullable {
 		switch c.DBType {
 		case "tinyint":
-			c.Type = "null.Int8"
+			// map tinyint(1) to bool if TinyintAsBool is true
+			if TinyintAsBool && c.FullDBType == "tinyint(1)" {
+				c.Type = "null.Bool"
+			} else {
+				c.Type = "null.Int8"
+			}
 		case "smallint":
 			c.Type = "null.Int16"
 		case "mediumint":
@@ -287,7 +301,12 @@ func (m *MySQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 	} else {
 		switch c.DBType {
 		case "tinyint":
-			c.Type = "int8"
+			// map tinyint(1) to bool if TinyintAsBool is true
+			if TinyintAsBool && c.FullDBType == "tinyint(1)" {
+				c.Type = "bool"
+			} else {
+				c.Type = "int8"
+			}
 		case "smallint":
 			c.Type = "int16"
 		case "mediumint":
diff --git a/main.go b/main.go
index b836181..3df0983 100644
--- a/main.go
+++ b/main.go
@@ -10,9 +10,10 @@ import (
 	"github.com/kat-co/vala"
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
+	"github.com/vattle/sqlboiler/bdb/drivers"
 )
 
-const sqlBoilerVersion = "2.1.3"
+const sqlBoilerVersion = "2.1.4"
 
 var (
 	cmdState  *State
@@ -82,6 +83,7 @@ func main() {
 	rootCmd.PersistentFlags().BoolP("no-hooks", "", false, "Disable hooks feature for your models")
 	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")
 
 	viper.SetDefault("postgres.sslmode", "require")
 	viper.SetDefault("postgres.port", "5432")
@@ -206,6 +208,9 @@ func preRun(cmd *cobra.Command, args []string) error {
 			SSLMode: viper.GetString("mysql.sslmode"),
 		}
 
+		// Set MySQL TinyintAsBool global var. This flag only applies to MySQL.
+		drivers.TinyintAsBool = viper.GetBool("tinyint-as-bool")
+
 		// MySQL doesn't have schemas, just databases
 		cmdConfig.Schema = cmdConfig.MySQL.DBName
 
diff --git a/testdata/mysql_test_schema.sql b/testdata/mysql_test_schema.sql
index 423aceb..a3b4af4 100644
--- a/testdata/mysql_test_schema.sql
+++ b/testdata/mysql_test_schema.sql
@@ -135,7 +135,9 @@ CREATE TABLE magicest (
   aaaa char NULL,
   bbbb char NOT NULL,
   cccc text NULL,
-  dddd text NOT NULL
+  dddd text NOT NULL,
+  eeee tinyint(2) NULL,
+  ffff tinyint(2) NOT NULL
 );
 
 create table owner (

From 920cb42f9baedb6e3295fdcdb654024ed63e2ebb Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Mon, 2 Jan 2017 15:20:32 +1000
Subject: [PATCH 005/179] Add examples for top level config

---
 README.md | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/README.md b/README.md
index 50a316a..428bf69 100644
--- a/README.md
+++ b/README.md
@@ -256,19 +256,20 @@ not to pass them through the command line or environment variables:
 Example:
 
 ```toml
+blacklist=["migrations", "other"]
+schema="myschema"
 [postgres]
-dbname="dbname"
-host="localhost"
-port=5432
-user="dbusername"
-pass="dbpassword"
-
+  dbname="dbname"
+  host="localhost"
+  port=5432
+  user="dbusername"
+  pass="dbpassword"
 [mysql]
-dbname="dbname"
-host="localhost"
-port=3306
-user="dbusername"
-pass="dbpassword"
+  dbname="dbname"
+  host="localhost"
+  port=3306
+  user="dbusername"
+  pass="dbpassword"
 sslmode="false"
 ```
 

From dd73656d8e04491027d3d99a222cda1f130e9f41 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Mon, 2 Jan 2017 15:21:16 +1000
Subject: [PATCH 006/179] Fix readme example spacing

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 428bf69..3f01292 100644
--- a/README.md
+++ b/README.md
@@ -270,7 +270,7 @@ schema="myschema"
   port=3306
   user="dbusername"
   pass="dbpassword"
-sslmode="false"
+  sslmode="false"
 ```
 
 #### Initial Generation

From 23b6221f8bb02da704b065d7eb441d80b6692623 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 3 Jan 2017 19:07:00 -0800
Subject: [PATCH 007/179] Relax the definition of unique on columns (mysql)

- Fix #77
---
 bdb/drivers/mysql.go | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go
index 4e74232..a803f4a 100644
--- a/bdb/drivers/mysql.go
+++ b/bdb/drivers/mysql.go
@@ -139,7 +139,8 @@ func (m *MySQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
 			inner join information_schema.key_column_usage kcu
 				on tc.constraint_name = kcu.constraint_name and tc.table_name = kcu.table_name and tc.table_schema = kcu.table_schema
 			where c.column_name = kcu.column_name and tc.table_name = c.table_name and
-				(tc.constraint_type = 'PRIMARY KEY' or tc.constraint_type = 'UNIQUE')
+				(tc.constraint_type = 'PRIMARY KEY' or tc.constraint_type = 'UNIQUE') and
+				(select count(*) from information_schema.key_column_usage where constraint_name = tc.constraint_name) = 1
 		) as is_unique
 	from information_schema.columns as c
 	where table_name = ? and table_schema = ?;

From 5f7bee14a032f31e4e560923dd282a97661f51f0 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 3 Jan 2017 19:43:01 -0800
Subject: [PATCH 008/179] Relax the definition of unique on columns (psql)

- Fix formatting on giant postgres query
- Invert the section that looks for unique constraints to look for a
  constraint and join to the constraint_column_usage to be more in line
  with the mysql query and also it makes a little bit more sense.
- Add more checks to ensure the schema is being enforced in the postgres
  side of things as several pieces in the unique checks were missing it
  which would lead to false positives.
- Fix #77 for postgres
---
 bdb/drivers/postgres.go | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/bdb/drivers/postgres.go b/bdb/drivers/postgres.go
index d14fb1b..ce94561 100644
--- a/bdb/drivers/postgres.go
+++ b/bdb/drivers/postgres.go
@@ -155,16 +155,17 @@ func (p *PostgresDriver) Columns(schema, tableName string) ([]bdb.Column, error)
 		c.is_nullable = 'YES' as is_nullable,
 		(select exists(
 			select 1
-				from information_schema.constraint_column_usage as ccu
-			inner join information_schema.table_constraints tc on ccu.constraint_name = tc.constraint_name
-			where ccu.table_name = c.table_name and ccu.column_name = c.column_name and tc.constraint_type = 'UNIQUE'
-			)) OR (select exists(
+			from information_schema.table_constraints tc
+			inner join information_schema.constraint_column_usage as ccu on tc.constraint_name = ccu.constraint_name
+			where tc.table_schema = $1 and tc.constraint_type = 'UNIQUE' and ccu.constraint_schema = $1 and ccu.table_name = c.table_name and ccu.column_name = c.column_name and
+				(select count(*) from information_schema.constraint_column_usage where constraint_schema = $1 and constraint_name = tc.constraint_name) = 1
+		)) OR
+		(select exists(
 			select 1
-			from
-				pg_indexes pgix
-				inner join pg_class pgc on pgix.indexname = pgc.relname and pgc.relkind = 'i'
-				inner join pg_index pgi on pgi.indexrelid = pgc.oid
-				inner join pg_attribute pga on pga.attrelid = pgi.indrelid and pga.attnum = ANY(pgi.indkey)
+			from pg_indexes pgix
+			inner join pg_class pgc on pgix.indexname = pgc.relname and pgc.relkind = 'i' and pgc.relnatts = 1
+			inner join pg_index pgi on pgi.indexrelid = pgc.oid
+			inner join pg_attribute pga on pga.attrelid = pgi.indrelid and pga.attnum = ANY(pgi.indkey)
 			where
 				pgix.schemaname = $1 and pgix.tablename = c.table_name and pga.attname = c.column_name and pgi.indisunique = true
 		)) as is_unique
@@ -173,7 +174,7 @@ func (p *PostgresDriver) Columns(schema, tableName string) ([]bdb.Column, error)
 		left join information_schema.element_types e
 			on ((c.table_catalog, c.table_schema, c.table_name, 'TABLE', c.dtd_identifier)
 			= (e.object_catalog, e.object_schema, e.object_name, e.object_type, e.collection_type_identifier))
-		where c.table_name=$2 and c.table_schema = $1;
+		where c.table_name = $2 and c.table_schema = $1;
 	`, schema, tableName)
 
 	if err != nil {

From 14b9122a087fdc952d971c51611f3e558a5981d6 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 3 Jan 2017 20:29:43 -0800
Subject: [PATCH 009/179] Fix underspecification of constraint lookups.

---
 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 a803f4a..1d80634 100644
--- a/bdb/drivers/mysql.go
+++ b/bdb/drivers/mysql.go
@@ -140,7 +140,7 @@ func (m *MySQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
 				on tc.constraint_name = kcu.constraint_name and tc.table_name = kcu.table_name and tc.table_schema = kcu.table_schema
 			where c.column_name = kcu.column_name and tc.table_name = c.table_name and
 				(tc.constraint_type = 'PRIMARY KEY' or tc.constraint_type = 'UNIQUE') and
-				(select count(*) from information_schema.key_column_usage where constraint_name = tc.constraint_name) = 1
+				(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 = ?;

From 4ae933653838c0ed6e0accef855856dd0f5e6141 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Wed, 4 Jan 2017 20:31:29 -0800
Subject: [PATCH 010/179] Fix bug in ToManySetOpsAdd and impure join tables

- This is a bug that manifests itself a bunch with our update code where
  you cannot actually use the update method to update a key since it
  uses the values on the struct to both update the values and find the
  object to update but in this operation the key must have two different
  values.
---
 templates/12_relationship_to_many_setops.tpl | 34 ++++++++++++++++----
 1 file changed, 27 insertions(+), 7 deletions(-)

diff --git a/templates/12_relationship_to_many_setops.tpl b/templates/12_relationship_to_many_setops.tpl
index cfa0819..0f92342 100644
--- a/templates/12_relationship_to_many_setops.tpl
+++ b/templates/12_relationship_to_many_setops.tpl
@@ -6,6 +6,8 @@
 		{{- $txt := txtsFromToMany $dot.Tables $table . -}}
 		{{- $varNameSingular := .Table | singular | camelCase -}}
 		{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase}}
+		{{- $foreignPKeyCols := (getTable $dot.Tables .ForeignTable).PKey.Columns -}}
+		{{- $foreignSchemaTable := .ForeignTable | $dot.SchemaTable}}
 // Add{{$txt.Function.Name}} adds the given related objects to the existing relationships
 // of the {{$table.Name | singular}}, optionally inserting them as new records.
 // Appends related to o.R.{{$txt.Function.Name}}.
@@ -13,20 +15,38 @@
 func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}(exec boil.Executor, insert bool, related ...*{{$txt.ForeignTable.NameGo}}) error {
 	var err error
 	for _, rel := range related {
-		{{if not .ToJoinTable -}}
-		rel.{{$txt.Function.ForeignAssignment}} = o.{{$txt.Function.LocalAssignment}}
-			{{if .ForeignColumnNullable -}}
-		rel.{{$txt.ForeignTable.ColumnNameGo}}.Valid = true
-			{{end -}}
-		{{end -}}
 		if insert {
+			{{if not .ToJoinTable -}}
+			rel.{{$txt.Function.ForeignAssignment}} = o.{{$txt.Function.LocalAssignment}}
+				{{if .ForeignColumnNullable -}}
+			rel.{{$txt.ForeignTable.ColumnNameGo}}.Valid = true
+				{{end -}}
+			{{end -}}
+
 			if err = rel.Insert(exec); err != nil {
 				return errors.Wrap(err, "failed to insert into foreign table")
 			}
 		}{{if not .ToJoinTable}} else {
-			if err = rel.Update(exec, "{{.ForeignColumn}}"); err != nil {
+			updateQuery := fmt.Sprintf(
+				"UPDATE {{$foreignSchemaTable}} SET %s WHERE %s",
+				strmangle.SetParamNames("{{$dot.LQ}}", "{{$dot.RQ}}", {{if $dot.Dialect.IndexPlaceholders}}1{{else}}0{{end}}, []string{{"{"}}"{{.ForeignColumn}}"{{"}"}}),
+				strmangle.WhereClause("{{$dot.LQ}}", "{{$dot.RQ}}", {{if $dot.Dialect.IndexPlaceholders}}2{{else}}0{{end}}, {{$foreignVarNameSingular}}PrimaryKeyColumns),
+			)
+			values := []interface{}{o.{{$txt.LocalTable.ColumnNameGo}}, rel.{{$foreignPKeyCols | stringMap $dot.StringFuncs.titleCase | join ", rel."}}{{"}"}}
+
+			if boil.DebugMode {
+				fmt.Fprintln(boil.DebugWriter, updateQuery)
+				fmt.Fprintln(boil.DebugWriter, values)
+			}
+
+			if _, err = exec.Exec(updateQuery, values...); err != nil {
 				return errors.Wrap(err, "failed to update foreign table")
 			}
+
+			rel.{{$txt.Function.ForeignAssignment}} = o.{{$txt.Function.LocalAssignment}}
+			{{if .ForeignColumnNullable -}}
+			rel.{{$txt.ForeignTable.ColumnNameGo}}.Valid = true
+			{{end -}}
 		}{{end -}}
 	}
 

From 22f7a45847c8b77adab9ab31a69736eeaf5b7183 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Thu, 5 Jan 2017 21:31:43 -0800
Subject: [PATCH 011/179] Ignore empty errors on postgres upsert fail

- Postgres's behavior when there is no update is that there is an
  ErrNoRows thrown back, which we can safely ignore since the only time
  this can happen in postgres's case is under this circumstance since
  there's no race unlike the mysql upsert code.
- Fix #84
---
 templates/17_upsert.tpl | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index f9f0f55..cf3b635 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -181,11 +181,14 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if ne .DriverName
 	{{- else}}
 	if len(cache.retMapping) != 0 {
 		err = exec.QueryRow(cache.query, vals...).Scan(returns...)
+		if err == sql.ErrNoRows {
+			err = nil // Postgres doesn't return anything when there's no update
+		}
 	} else {
 		_, err = exec.Exec(cache.query, vals...)
 	}
 	if err != nil {
-		return errors.Wrap(err, "{{.PkgName}}: unable to upsert for {{.Table.Name}}")
+		return errors.Wrap(err, "{{.PkgName}}: unable to upsert {{.Table.Name}}")
 	}
 	{{- end}}
 

From 158d9cbec0b37aec9b80c4205d02626f1021bd41 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sat, 7 Jan 2017 00:48:39 +1000
Subject: [PATCH 012/179] remove commas from schema example

---
 README.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 3f01292..a272fc2 100644
--- a/README.md
+++ b/README.md
@@ -342,7 +342,7 @@ Most examples in this section will be demonstrated using the following Postgres
 ```sql
 CREATE TABLE pilots (
   id integer NOT NULL,
-  name text NOT NULL,
+  name text NOT NULL
 );
 
 ALTER TABLE pilots ADD CONSTRAINT pilot_pkey PRIMARY KEY (id);
@@ -352,7 +352,7 @@ CREATE TABLE jets (
   pilot_id integer NOT NULL,
   age integer NOT NULL,
   name text NOT NULL,
-  color text NOT NULL,
+  color text NOT NULL
 );
 
 ALTER TABLE jets ADD CONSTRAINT jet_pkey PRIMARY KEY (id);

From be2131c7639dbb64df3e935c2887540c9d29d55a Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sat, 7 Jan 2017 01:00:02 +1000
Subject: [PATCH 013/179] Bump to 2.1.5

* Includes fix #77 #82 (to one associations erroneously generated)
* Includes readme update
---
 main.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/main.go b/main.go
index 3df0983..7cca6d6 100644
--- a/main.go
+++ b/main.go
@@ -13,7 +13,7 @@ import (
 	"github.com/vattle/sqlboiler/bdb/drivers"
 )
 
-const sqlBoilerVersion = "2.1.4"
+const sqlBoilerVersion = "2.1.5"
 
 var (
 	cmdState  *State

From fac1a7fe6941c3200e39bfbbdf71090c710aaa8e Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sat, 7 Jan 2017 01:17:28 +1000
Subject: [PATCH 014/179] update schemas to incl broken example from readme

---
 testdata/mysql_test_schema.sql    | 69 ++++++++++++++++---------------
 testdata/postgres_test_schema.sql | 69 ++++++++++++++++---------------
 2 files changed, 71 insertions(+), 67 deletions(-)

diff --git a/testdata/mysql_test_schema.sql b/testdata/mysql_test_schema.sql
index a3b4af4..4755a63 100644
--- a/testdata/mysql_test_schema.sql
+++ b/testdata/mysql_test_schema.sql
@@ -240,40 +240,6 @@ create table worms (
   foreign key (tiger_id) references tigers (id)
 );
 
-create table pilots (
-  id   int primary key not null auto_increment,
-  name varchar(255)
-);
-
-create table airports (
-  id   int primary key not null auto_increment,
-  name varchar(255)
-);
-
-create table languages (
-  id   int primary key not null auto_increment,
-  name varchar(255)
-);
-
-create table jets (
-  id         int primary key not null auto_increment,
-  name       varchar(255),
-  pilot_id   integer,
-  airport_id integer,
-
-  foreign key (pilot_id) references pilots (id),
-  foreign key (airport_id) references airports (id)
-);
-
-create table pilot_languages (
-  pilot_id    integer not null,
-  language_id integer not null,
-
-  primary key (pilot_id, language_id),
-  foreign key (pilot_id) references pilots (id),
-  foreign key (language_id) references languages (id)
-);
-
 create table byte_pilots (
   id   binary primary key not null,
   name varchar(255)
@@ -351,3 +317,38 @@ CREATE TABLE race_result_scratchings (
     foreign key (results_id) references race_results(id)
 );
 
+CREATE TABLE pilots (
+  id integer NOT NULL,
+  name text NOT NULL
+);
+
+ALTER TABLE pilots ADD CONSTRAINT pilot_pkey PRIMARY KEY (id);
+
+CREATE TABLE jets (
+  id integer NOT NULL,
+  pilot_id integer NOT NULL,
+  age integer NOT NULL,
+  name text NOT NULL,
+  color text NOT NULL
+);
+
+ALTER TABLE jets ADD CONSTRAINT jet_pkey PRIMARY KEY (id);
+ALTER TABLE jets ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
+
+CREATE TABLE languages (
+  id integer NOT NULL,
+  language text NOT NULL
+);
+
+ALTER TABLE languages ADD CONSTRAINT language_pkey PRIMARY KEY (id);
+
+-- Join table
+CREATE TABLE pilot_languages (
+  pilot_id integer NOT NULL,
+  language_id integer NOT NULL
+);
+
+-- Composite primary key
+ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pkey PRIMARY KEY (pilot_id, language_id);
+ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
+ALTER TABLE pilot_languages ADD CONSTRAINT languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id);
diff --git a/testdata/postgres_test_schema.sql b/testdata/postgres_test_schema.sql
index 7a3893e..52f33e4 100644
--- a/testdata/postgres_test_schema.sql
+++ b/testdata/postgres_test_schema.sql
@@ -246,7 +246,6 @@ create table enemies (
   primary key (enemies)
 );
 
-
 create table chocolate (
   dog varchar(100) primary key
 );
@@ -307,38 +306,6 @@ create table worms (
   foreign key (tiger_id) references tigers (id)
 );
 
-create table pilots (
-  id   serial primary key not null,
-  name character varying
-);
-
-create table airports (
-  id   serial primary key not null,
-  name character varying
-);
-
-create table languages (
-  id   serial primary key not null,
-  name character varying
-);
-
-create table jets (
-  id         serial primary key not null,
-  name       character varying,
-  pilot_id   integer,
-  airport_id integer,
-  foreign key (pilot_id) references pilots (id),
-  foreign key (airport_id) references airports (id)
-);
-
-create table pilot_languages (
-  pilot_id    integer not null,
-  language_id integer not null,
-
-  primary key (pilot_id, language_id),
-  foreign key (pilot_id) references pilots (id),
-  foreign key (language_id) references languages (id)
-);
 
 create table byte_pilots (
   id   bytea primary key not null,
@@ -416,3 +383,39 @@ CREATE TABLE race_result_scratchings (
     name text NOT NULL,
     foreign key (results_id) references race_results(id)
 );
+
+CREATE TABLE pilots (
+  id integer NOT NULL,
+  name text NOT NULL
+);
+
+ALTER TABLE pilots ADD CONSTRAINT pilot_pkey PRIMARY KEY (id);
+
+CREATE TABLE jets (
+  id integer NOT NULL,
+  pilot_id integer NOT NULL,
+  age integer NOT NULL,
+  name text NOT NULL,
+  color text NOT NULL
+);
+
+ALTER TABLE jets ADD CONSTRAINT jet_pkey PRIMARY KEY (id);
+ALTER TABLE jets ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
+
+CREATE TABLE languages (
+  id integer NOT NULL,
+  language text NOT NULL
+);
+
+ALTER TABLE languages ADD CONSTRAINT language_pkey PRIMARY KEY (id);
+
+-- Join table
+CREATE TABLE pilot_languages (
+  pilot_id integer NOT NULL,
+  language_id integer NOT NULL
+);
+
+-- Composite primary key
+ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pkey PRIMARY KEY (pilot_id, language_id);
+ALTER TABLE pilot_languages ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
+ALTER TABLE pilot_languages ADD CONSTRAINT languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id);

From 711ecbbe8d24dbb3b317ad3930b356344a894fbc Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Fri, 6 Jan 2017 17:45:32 -0800
Subject: [PATCH 015/179] Use pg-specific schema tables for fkey detection

- Postgres doesn't care about names for uniqueness of keys unlike mysql
  because internally it keeps "oid" values to keep track of everything.
  Unfortunately this means that the information_schema standard is
  inadequate to differentiate between constraints that are named the
  same (which isn't possible in mysql, but is in pg). Hence we have to
  dip into the pg specific schemas for better or worse.
- Fix naming of the sample schema in the README since it would fail for
  mysql due to duplicate naming.
- Mark test schema up so we don't fix the bad names so we catch
  regressions here.
- Fix #85
---
 README.md                         |  6 +++---
 bdb/drivers/postgres.go           | 21 ++++++++++++---------
 testdata/postgres_test_schema.sql |  2 ++
 3 files changed, 17 insertions(+), 12 deletions(-)

diff --git a/README.md b/README.md
index a272fc2..ac8159a 100644
--- a/README.md
+++ b/README.md
@@ -356,7 +356,7 @@ CREATE TABLE jets (
 );
 
 ALTER TABLE jets ADD CONSTRAINT jet_pkey PRIMARY KEY (id);
-ALTER TABLE jets ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
+ALTER TABLE jets ADD CONSTRAINT jet_pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
 
 CREATE TABLE languages (
   id integer NOT NULL,
@@ -373,8 +373,8 @@ CREATE TABLE pilot_languages (
 
 -- Composite primary key
 ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pkey PRIMARY KEY (pilot_id, language_id);
-ALTER TABLE pilot_languages ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
-ALTER TABLE pilot_languages ADD CONSTRAINT languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id);
+ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
+ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id);
 ```
 
 The generated model structs for this schema look like the following. Note that we've included the relationship
diff --git a/bdb/drivers/postgres.go b/bdb/drivers/postgres.go
index ce94561..5ae0283 100644
--- a/bdb/drivers/postgres.go
+++ b/bdb/drivers/postgres.go
@@ -264,15 +264,18 @@ func (p *PostgresDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.Foreign
 
 	query := `
 	select
-		tc.constraint_name,
-		kcu.table_name as source_table,
-		kcu.column_name as source_column,
-		ccu.table_name as dest_table,
-		ccu.column_name as dest_column
-	from information_schema.table_constraints as tc
-		inner join information_schema.key_column_usage as kcu ON tc.constraint_name = kcu.constraint_name and tc.constraint_schema = kcu.constraint_schema
-		inner join information_schema.constraint_column_usage as ccu ON tc.constraint_name = ccu.constraint_name and tc.constraint_schema = ccu.constraint_schema
-	where tc.table_name = $1 and tc.constraint_type = 'FOREIGN KEY' and tc.table_schema = $2;`
+		pgcon.conname,
+		pgc.relname as source_table,
+		pgasrc.attname as source_column,
+		dstlookupname.relname as dest_table,
+		pgadst.attname as dest_column
+	from pg_namespace pgn
+		inner join pg_class pgc on pgn.oid = pgc.relnamespace and pgc.relkind = 'r'
+		inner join pg_constraint pgcon on pgn.oid = pgcon.connamespace and pgc.oid = pgcon.conrelid
+		inner join pg_class dstlookupname on pgcon.confrelid = dstlookupname.oid
+		inner join pg_attribute pgasrc on pgc.oid = pgasrc.attrelid and pgasrc.attnum = ANY(pgcon.conkey)
+		inner join pg_attribute pgadst on pgcon.confrelid = pgadst.attrelid and pgadst.attnum = ANY(pgcon.confkey)
+	where pgn.nspname = $2 and pgc.relname = $1 and pgcon.contype = 'f'`
 
 	var rows *sql.Rows
 	var err error
diff --git a/testdata/postgres_test_schema.sql b/testdata/postgres_test_schema.sql
index 52f33e4..e0a043c 100644
--- a/testdata/postgres_test_schema.sql
+++ b/testdata/postgres_test_schema.sql
@@ -400,6 +400,7 @@ CREATE TABLE jets (
 );
 
 ALTER TABLE jets ADD CONSTRAINT jet_pkey PRIMARY KEY (id);
+-- The following fkey remains poorly named to avoid regressions related to psql naming
 ALTER TABLE jets ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
 
 CREATE TABLE languages (
@@ -417,5 +418,6 @@ CREATE TABLE pilot_languages (
 
 -- Composite primary key
 ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pkey PRIMARY KEY (pilot_id, language_id);
+-- The following fkey remains poorly named to avoid regressions related to psql naming
 ALTER TABLE pilot_languages ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
 ALTER TABLE pilot_languages ADD CONSTRAINT languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id);

From 4997ba96bf27b05757e170dee7de1b0865b25d5d Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Mon, 9 Jan 2017 20:28:07 -0800
Subject: [PATCH 016/179] Add more clear documentation about boil.Begin()

- Fix #88
---
 README.md | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/README.md b/README.md
index ac8159a..1479d6c 100644
--- a/README.md
+++ b/README.md
@@ -558,6 +558,9 @@ err := pilot.Delete(db) // Regular variant, takes a db handle (boil.Executor int
 pilot.DeleteP(db)       // Panic variant, takes a db handle and panics on error.
 err := pilot.DeleteG()  // Global variant, uses the globally set db handle (boil.SetDB()).
 pilot.DeleteGP()        // Global&Panic variant, combines the global db handle and panic on error.
+
+db.Begin()              // Normal sql package way of creating a transaction
+boil.Begin()            // Uses the global database handle set by boil.SetDB()
 ```
 
 Note that it's slightly different for query building.
@@ -857,6 +860,10 @@ tx.Commit()
 tx.Rollback()
 ```
 
+It's also worth noting that there's a way to take advantage of `boil.SetDB()`
+by using the [boil.Begin()](https://godoc.org/github.com/vattle/sqlboiler/boil#Begin) function.
+This opens a transaction using the globally stored database.
+
 ### Debug Logging
 
 Debug logging will print your generated SQL statement and the arguments it is using.

From 61ab7e254a192046c1351b84fb0c00eaf756a029 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Mon, 9 Jan 2017 21:06:47 -0800
Subject: [PATCH 017/179] Add missing function variants for setops.

- Fix #87
---
 templates/10_relationship_to_one_setops.tpl   | 56 +++++++++++
 .../11_relationship_one_to_one_setops.tpl     | 56 +++++++++++
 templates/12_relationship_to_many_setops.tpl  | 96 +++++++++++++++++++
 3 files changed, 208 insertions(+)

diff --git a/templates/10_relationship_to_one_setops.tpl b/templates/10_relationship_to_one_setops.tpl
index 728ab10..14f726e 100644
--- a/templates/10_relationship_to_one_setops.tpl
+++ b/templates/10_relationship_to_one_setops.tpl
@@ -6,6 +6,34 @@
 		{{- $foreignNameSingular := .ForeignTable | singular | camelCase -}}
 		{{- $varNameSingular := .Table | singular | camelCase}}
 		{{- $schemaTable := .Table | $dot.SchemaTable}}
+// Set{{$txt.Function.Name}}G of the {{.Table | singular}} to the related item.
+// Sets o.R.{{$txt.Function.Name}} to related.
+// Adds o to related.R.{{$txt.Function.ForeignName}}.
+// Uses the global database handle.
+func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}G(insert bool, related *{{$txt.ForeignTable.NameGo}}) error {
+	return o.Set{{$txt.Function.Name}}(boil.GetDB(), insert, related)
+}
+
+// Set{{$txt.Function.Name}}P of the {{.Table | singular}} to the related item.
+// Sets o.R.{{$txt.Function.Name}} to related.
+// Adds o to related.R.{{$txt.Function.ForeignName}}.
+// Panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}P(exec boil.Executor, insert bool, related *{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Set{{$txt.Function.Name}}(exec, insert, related); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
+// Set{{$txt.Function.Name}}GP of the {{.Table | singular}} to the related item.
+// Sets o.R.{{$txt.Function.Name}} to related.
+// Adds o to related.R.{{$txt.Function.ForeignName}}.
+// Uses the global database handle and panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}GP(insert bool, related *{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Set{{$txt.Function.Name}}(boil.GetDB(), insert, related); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
 // Set{{$txt.Function.Name}} of the {{.Table | singular}} to the related item.
 // Sets o.R.{{$txt.Function.Name}} to related.
 // Adds o to related.R.{{$txt.Function.ForeignName}}.
@@ -68,6 +96,34 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 }
 
 		{{- if .Nullable}}
+// Remove{{$txt.Function.Name}}G relationship.
+// Sets o.R.{{$txt.Function.Name}} to nil.
+// Removes o from all passed in related items' relationships struct (Optional).
+// Uses the global database handle.
+func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}G(related *{{$txt.ForeignTable.NameGo}}) error {
+	return o.Remove{{$txt.Function.Name}}(boil.GetDB(), related)
+}
+
+// Remove{{$txt.Function.Name}}P relationship.
+// Sets o.R.{{$txt.Function.Name}} to nil.
+// Removes o from all passed in related items' relationships struct (Optional).
+// Panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}P(exec boil.Executor, related *{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Remove{{$txt.Function.Name}}(exec, related); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
+// Remove{{$txt.Function.Name}}GP relationship.
+// Sets o.R.{{$txt.Function.Name}} to nil.
+// Removes o from all passed in related items' relationships struct (Optional).
+// Uses the global database handle and panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}GP(related *{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Remove{{$txt.Function.Name}}(boil.GetDB(), related); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
 // Remove{{$txt.Function.Name}} relationship.
 // Sets o.R.{{$txt.Function.Name}} to nil.
 // Removes o from all passed in related items' relationships struct (Optional).
diff --git a/templates/11_relationship_one_to_one_setops.tpl b/templates/11_relationship_one_to_one_setops.tpl
index 7466d7a..826eec2 100644
--- a/templates/11_relationship_one_to_one_setops.tpl
+++ b/templates/11_relationship_one_to_one_setops.tpl
@@ -7,6 +7,34 @@
 		{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase -}}
 		{{- $foreignPKeyCols := (getTable $dot.Tables .ForeignTable).PKey.Columns -}}
 		{{- $foreignSchemaTable := .ForeignTable | $dot.SchemaTable}}
+// Set{{$txt.Function.Name}}G of the {{.Table | singular}} to the related item.
+// Sets o.R.{{$txt.Function.Name}} to related.
+// Adds o to related.R.{{$txt.Function.ForeignName}}.
+// Uses the global database handle.
+func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}G(insert bool, related *{{$txt.ForeignTable.NameGo}}) error {
+	return o.Set{{$txt.Function.Name}}(boil.GetDB(), insert, related)
+}
+
+// Set{{$txt.Function.Name}}P of the {{.Table | singular}} to the related item.
+// Sets o.R.{{$txt.Function.Name}} to related.
+// Adds o to related.R.{{$txt.Function.ForeignName}}.
+// Panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}P(exec boil.Executor, insert bool, related *{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Set{{$txt.Function.Name}}(exec, insert, related); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
+// Set{{$txt.Function.Name}}GP of the {{.Table | singular}} to the related item.
+// Sets o.R.{{$txt.Function.Name}} to related.
+// Adds o to related.R.{{$txt.Function.ForeignName}}.
+// Uses the global database handle and panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}GP(insert bool, related *{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Set{{$txt.Function.Name}}(boil.GetDB(), insert, related); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
 // Set{{$txt.Function.Name}} of the {{.Table | singular}} to the related item.
 // Sets o.R.{{$txt.Function.Name}} to related.
 // Adds o to related.R.{{$txt.Function.ForeignName}}.
@@ -65,6 +93,34 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 }
 
 		{{- if .ForeignColumnNullable}}
+// Remove{{$txt.Function.Name}}G relationship.
+// Sets o.R.{{$txt.Function.Name}} to nil.
+// Removes o from all passed in related items' relationships struct (Optional).
+// Uses the global database handle.
+func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}G(related *{{$txt.ForeignTable.NameGo}}) error {
+	return o.Remove{{$txt.Function.Name}}(boil.GetDB(), related)
+}
+
+// Remove{{$txt.Function.Name}}P relationship.
+// Sets o.R.{{$txt.Function.Name}} to nil.
+// Removes o from all passed in related items' relationships struct (Optional).
+// Panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}P(exec boil.Executor, related *{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Remove{{$txt.Function.Name}}(exec, related); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
+// Remove{{$txt.Function.Name}}GP relationship.
+// Sets o.R.{{$txt.Function.Name}} to nil.
+// Removes o from all passed in related items' relationships struct (Optional).
+// Uses the global database handle and panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}GP(related *{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Remove{{$txt.Function.Name}}(boil.GetDB(), related); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
 // Remove{{$txt.Function.Name}} relationship.
 // Sets o.R.{{$txt.Function.Name}} to nil.
 // Removes o from all passed in related items' relationships struct (Optional).
diff --git a/templates/12_relationship_to_many_setops.tpl b/templates/12_relationship_to_many_setops.tpl
index 0f92342..04c1b97 100644
--- a/templates/12_relationship_to_many_setops.tpl
+++ b/templates/12_relationship_to_many_setops.tpl
@@ -8,6 +8,37 @@
 		{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase}}
 		{{- $foreignPKeyCols := (getTable $dot.Tables .ForeignTable).PKey.Columns -}}
 		{{- $foreignSchemaTable := .ForeignTable | $dot.SchemaTable}}
+// Add{{$txt.Function.Name}}G adds the given related objects to the existing relationships
+// of the {{$table.Name | singular}}, optionally inserting them as new records.
+// Appends related to o.R.{{$txt.Function.Name}}.
+// Sets related.R.{{$txt.Function.ForeignName}} appropriately.
+// Uses the global database handle.
+func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}G(insert bool, related ...*{{$txt.ForeignTable.NameGo}}) error {
+	return o.Add{{$txt.Function.Name}}(boil.GetDB(), insert, related...)
+}
+
+// Add{{$txt.Function.Name}}P adds the given related objects to the existing relationships
+// of the {{$table.Name | singular}}, optionally inserting them as new records.
+// Appends related to o.R.{{$txt.Function.Name}}.
+// Sets related.R.{{$txt.Function.ForeignName}} appropriately.
+// Panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}P(exec boil.Executor, insert bool, related ...*{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Add{{$txt.Function.Name}}(exec, insert, related...); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
+// Add{{$txt.Function.Name}}GP adds the given related objects to the existing relationships
+// of the {{$table.Name | singular}}, optionally inserting them as new records.
+// Appends related to o.R.{{$txt.Function.Name}}.
+// Sets related.R.{{$txt.Function.ForeignName}} appropriately.
+// Uses the global database handle and panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}GP(insert bool, related ...*{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Add{{$txt.Function.Name}}(boil.GetDB(), insert, related...); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
 // Add{{$txt.Function.Name}} adds the given related objects to the existing relationships
 // of the {{$table.Name | singular}}, optionally inserting them as new records.
 // Appends related to o.R.{{$txt.Function.Name}}.
@@ -101,6 +132,43 @@ func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}(exec boil.Executo
 }
 
 			{{- if (or .ForeignColumnNullable .ToJoinTable)}}
+// Set{{$txt.Function.Name}}G removes all previously related items of the
+// {{$table.Name | singular}} replacing them completely with the passed
+// in related items, optionally inserting them as new records.
+// Sets o.R.{{$txt.Function.ForeignName}}'s {{$txt.Function.Name}} accordingly.
+// Replaces o.R.{{$txt.Function.Name}} with related.
+// Sets related.R.{{$txt.Function.ForeignName}}'s {{$txt.Function.Name}} accordingly.
+// Uses the global database handle.
+func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}G(insert bool, related ...*{{$txt.ForeignTable.NameGo}}) error {
+	return o.Set{{$txt.Function.Name}}(boil.GetDB(), insert, related...)
+}
+
+// Set{{$txt.Function.Name}}P removes all previously related items of the
+// {{$table.Name | singular}} replacing them completely with the passed
+// in related items, optionally inserting them as new records.
+// Sets o.R.{{$txt.Function.ForeignName}}'s {{$txt.Function.Name}} accordingly.
+// Replaces o.R.{{$txt.Function.Name}} with related.
+// Sets related.R.{{$txt.Function.ForeignName}}'s {{$txt.Function.Name}} accordingly.
+// Panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}P(exec boil.Executor, insert bool, related ...*{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Set{{$txt.Function.Name}}(exec, insert, related...); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
+// Set{{$txt.Function.Name}}GP removes all previously related items of the
+// {{$table.Name | singular}} replacing them completely with the passed
+// in related items, optionally inserting them as new records.
+// Sets o.R.{{$txt.Function.ForeignName}}'s {{$txt.Function.Name}} accordingly.
+// Replaces o.R.{{$txt.Function.Name}} with related.
+// Sets related.R.{{$txt.Function.ForeignName}}'s {{$txt.Function.Name}} accordingly.
+// Uses the global database handle and panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}GP(insert bool, related ...*{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Set{{$txt.Function.Name}}(boil.GetDB(), insert, related...); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
 // Set{{$txt.Function.Name}} removes all previously related items of the
 // {{$table.Name | singular}} replacing them completely with the passed
 // in related items, optionally inserting them as new records.
@@ -146,6 +214,34 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 	return o.Add{{$txt.Function.Name}}(exec, insert, related...)
 }
 
+// Remove{{$txt.Function.Name}}G relationships from objects passed in.
+// Removes related items from R.{{$txt.Function.Name}} (uses pointer comparison, removal does not keep order)
+// Sets related.R.{{$txt.Function.ForeignName}}.
+// Uses the global database handle.
+func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}G(related ...*{{$txt.ForeignTable.NameGo}}) error {
+	return o.Remove{{$txt.Function.Name}}(boil.GetDB(), related...)
+}
+
+// Remove{{$txt.Function.Name}}P relationships from objects passed in.
+// Removes related items from R.{{$txt.Function.Name}} (uses pointer comparison, removal does not keep order)
+// Sets related.R.{{$txt.Function.ForeignName}}.
+// Panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}P(exec boil.Executor, related ...*{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Remove{{$txt.Function.Name}}(exec, related...); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
+// Remove{{$txt.Function.Name}}GP relationships from objects passed in.
+// Removes related items from R.{{$txt.Function.Name}} (uses pointer comparison, removal does not keep order)
+// Sets related.R.{{$txt.Function.ForeignName}}.
+// Uses the global database handle and panics on error.
+func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}GP(related ...*{{$txt.ForeignTable.NameGo}}) {
+	if err := o.Remove{{$txt.Function.Name}}(boil.GetDB(), related...); err != nil {
+		panic(boil.WrapErr(err))
+	}
+}
+
 // Remove{{$txt.Function.Name}} relationships from objects passed in.
 // Removes related items from R.{{$txt.Function.Name}} (uses pointer comparison, removal does not keep order)
 // Sets related.R.{{$txt.Function.ForeignName}}.

From aab85fd2cde5468e3347c3c9e6430e6230bec2be Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 10 Jan 2017 18:09:20 -0800
Subject: [PATCH 018/179] Add issue template.

---
 .github/ISSUE_TEMPLATE.md | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
 create mode 100644 .github/ISSUE_TEMPLATE.md

diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..062a49c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,18 @@
+If you're having a generation problem please answer these questions before submitting your issue. Thanks!
+
+### What version of SQLBoiler are you using (`sqlboiler --version`)?
+
+
+### If this happened at generation time what was the full SQLBoiler command you used to generate your models? (if not applicable leave blank)
+
+
+### If this happened at runtime what code produced the issue? (if not applicable leave blank)
+
+
+### What is the output of the command above with the `-d` flag added to it? (Provided you are comfortable sharing this, it contains a blueprint of your schema)
+
+
+### Please provide a relevant database schema so we can replicate your issue (Provided you are comfortable sharing this)
+
+
+### Further information. What did you do, what did you expect?

From ab01c9d234dddc4dcdcb77d30d05bf23ba3b0af4 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 10 Jan 2017 18:16:02 -0800
Subject: [PATCH 019/179] Don't eat so many spaces in to_many templates

- Fix #89
---
 templates_test/relationship_to_many.tpl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/templates_test/relationship_to_many.tpl b/templates_test/relationship_to_many.tpl
index d23984e..0080688 100644
--- a/templates_test/relationship_to_many.tpl
+++ b/templates_test/relationship_to_many.tpl
@@ -28,7 +28,7 @@ func test{{$txt.LocalTable.NameGo}}ToMany{{$txt.Function.Name}}(t *testing.T) {
 	{{if .Nullable -}}
 	a.{{.Column | titleCase}}.Valid = true
 	{{- end}}
-	{{- if .ForeignColumnNullable -}}
+	{{- if .ForeignColumnNullable}}
 	b.{{.ForeignColumn | titleCase}}.Valid = true
 	c.{{.ForeignColumn | titleCase}}.Valid = true
 	{{- end}}

From 88cde8df0cbf4b7855d55a7a308f17cfe5f34517 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sat, 14 Jan 2017 13:13:55 +1000
Subject: [PATCH 020/179] Made new core package to hold core of app

* This was primarily done so it can be used as a library in ABCWeb and
other apps.
---
 config.go => core/config.go                       |  2 +-
 sqlboiler.go => core/core.go                      |  2 +-
 sqlboiler_test.go => core/core_test.go            |  2 +-
 imports.go => core/imports.go                     |  2 +-
 imports_test.go => core/imports_test.go           |  2 +-
 output.go => core/output.go                       |  2 +-
 output_test.go => core/output_test.go             |  2 +-
 templates.go => core/templates.go                 |  2 +-
 templates_test.go => core/templates_test.go       |  2 +-
 text_helpers.go => core/text_helpers.go           |  2 +-
 text_helpers_test.go => core/text_helpers_test.go |  2 +-
 main.go                                           | 13 +++++++------
 12 files changed, 18 insertions(+), 17 deletions(-)
 rename config.go => core/config.go (98%)
 rename sqlboiler.go => core/core.go (99%)
 rename sqlboiler_test.go => core/core_test.go (99%)
 rename imports.go => core/imports.go (99%)
 rename imports_test.go => core/imports_test.go (99%)
 rename output.go => core/output.go (99%)
 rename output_test.go => core/output_test.go (99%)
 rename templates.go => core/templates.go (99%)
 rename templates_test.go => core/templates_test.go (98%)
 rename text_helpers.go => core/text_helpers.go (99%)
 rename text_helpers_test.go => core/text_helpers_test.go (99%)

diff --git a/config.go b/core/config.go
similarity index 98%
rename from config.go
rename to core/config.go
index da28134..a23f6f2 100644
--- a/config.go
+++ b/core/config.go
@@ -1,4 +1,4 @@
-package main
+package core
 
 // Config for the running of the commands
 type Config struct {
diff --git a/sqlboiler.go b/core/core.go
similarity index 99%
rename from sqlboiler.go
rename to core/core.go
index 0c52dce..a650559 100644
--- a/sqlboiler.go
+++ b/core/core.go
@@ -1,6 +1,6 @@
 // Package sqlboiler has types and methods useful for generating code that
 // acts as a fully dynamic ORM might.
-package main
+package core
 
 import (
 	"encoding/json"
diff --git a/sqlboiler_test.go b/core/core_test.go
similarity index 99%
rename from sqlboiler_test.go
rename to core/core_test.go
index 367e429..fc56d66 100644
--- a/sqlboiler_test.go
+++ b/core/core_test.go
@@ -1,4 +1,4 @@
-package main
+package core
 
 import (
 	"bufio"
diff --git a/imports.go b/core/imports.go
similarity index 99%
rename from imports.go
rename to core/imports.go
index f545a28..97be767 100644
--- a/imports.go
+++ b/core/imports.go
@@ -1,4 +1,4 @@
-package main
+package core
 
 import (
 	"bytes"
diff --git a/imports_test.go b/core/imports_test.go
similarity index 99%
rename from imports_test.go
rename to core/imports_test.go
index 628d955..4a919da 100644
--- a/imports_test.go
+++ b/core/imports_test.go
@@ -1,4 +1,4 @@
-package main
+package core
 
 import (
 	"reflect"
diff --git a/output.go b/core/output.go
similarity index 99%
rename from output.go
rename to core/output.go
index d6914c3..1ed13c9 100644
--- a/output.go
+++ b/core/output.go
@@ -1,4 +1,4 @@
-package main
+package core
 
 import (
 	"bufio"
diff --git a/output_test.go b/core/output_test.go
similarity index 99%
rename from output_test.go
rename to core/output_test.go
index 3a33eca..05e94c1 100644
--- a/output_test.go
+++ b/core/output_test.go
@@ -1,4 +1,4 @@
-package main
+package core
 
 import (
 	"bytes"
diff --git a/templates.go b/core/templates.go
similarity index 99%
rename from templates.go
rename to core/templates.go
index 9baae19..2da75b7 100644
--- a/templates.go
+++ b/core/templates.go
@@ -1,4 +1,4 @@
-package main
+package core
 
 import (
 	"fmt"
diff --git a/templates_test.go b/core/templates_test.go
similarity index 98%
rename from templates_test.go
rename to core/templates_test.go
index df45e1e..6dea42b 100644
--- a/templates_test.go
+++ b/core/templates_test.go
@@ -1,4 +1,4 @@
-package main
+package core
 
 import (
 	"sort"
diff --git a/text_helpers.go b/core/text_helpers.go
similarity index 99%
rename from text_helpers.go
rename to core/text_helpers.go
index 56451e6..2df5887 100644
--- a/text_helpers.go
+++ b/core/text_helpers.go
@@ -1,4 +1,4 @@
-package main
+package core
 
 import (
 	"fmt"
diff --git a/text_helpers_test.go b/core/text_helpers_test.go
similarity index 99%
rename from text_helpers_test.go
rename to core/text_helpers_test.go
index b203dd9..b879fb9 100644
--- a/text_helpers_test.go
+++ b/core/text_helpers_test.go
@@ -1,4 +1,4 @@
-package main
+package core
 
 import (
 	"reflect"
diff --git a/main.go b/main.go
index 7cca6d6..738df64 100644
--- a/main.go
+++ b/main.go
@@ -11,13 +11,14 @@ import (
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 	"github.com/vattle/sqlboiler/bdb/drivers"
+	"github.com/vattle/sqlboiler/core"
 )
 
 const sqlBoilerVersion = "2.1.5"
 
 var (
-	cmdState  *State
-	cmdConfig *Config
+	cmdState  *core.State
+	cmdConfig *core.Config
 )
 
 func main() {
@@ -122,7 +123,7 @@ func preRun(cmd *cobra.Command, args []string) error {
 
 	driverName := args[0]
 
-	cmdConfig = &Config{
+	cmdConfig = &core.Config{
 		DriverName:       driverName,
 		OutFolder:        viper.GetString("output"),
 		Schema:           viper.GetString("schema"),
@@ -163,7 +164,7 @@ func preRun(cmd *cobra.Command, args []string) error {
 	}
 
 	if driverName == "postgres" {
-		cmdConfig.Postgres = PostgresConfig{
+		cmdConfig.Postgres = core.PostgresConfig{
 			User:    viper.GetString("postgres.user"),
 			Pass:    viper.GetString("postgres.pass"),
 			Host:    viper.GetString("postgres.host"),
@@ -199,7 +200,7 @@ func preRun(cmd *cobra.Command, args []string) error {
 	}
 
 	if driverName == "mysql" {
-		cmdConfig.MySQL = MySQLConfig{
+		cmdConfig.MySQL = core.MySQLConfig{
 			User:    viper.GetString("mysql.user"),
 			Pass:    viper.GetString("mysql.pass"),
 			Host:    viper.GetString("mysql.host"),
@@ -240,7 +241,7 @@ func preRun(cmd *cobra.Command, args []string) error {
 		}
 	}
 
-	cmdState, err = New(cmdConfig)
+	cmdState, err = core.New(cmdConfig)
 	return err
 }
 

From 788d28400ec710c137b756612633fb2fee1db701 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sat, 14 Jan 2017 13:38:40 +1000
Subject: [PATCH 021/179] rename core to boilingcore to make a more sense

* make more sense as a third party library
---
 core/core.go => boilingcore/boilingcore.go         |  2 +-
 .../boilingcore_test.go                            |  2 +-
 {core => boilingcore}/config.go                    |  2 +-
 {core => boilingcore}/imports.go                   |  2 +-
 {core => boilingcore}/imports_test.go              |  2 +-
 {core => boilingcore}/output.go                    |  2 +-
 {core => boilingcore}/output_test.go               |  2 +-
 {core => boilingcore}/templates.go                 |  2 +-
 {core => boilingcore}/templates_test.go            |  2 +-
 {core => boilingcore}/text_helpers.go              |  2 +-
 {core => boilingcore}/text_helpers_test.go         |  2 +-
 main.go                                            | 14 +++++++-------
 12 files changed, 18 insertions(+), 18 deletions(-)
 rename core/core.go => boilingcore/boilingcore.go (99%)
 rename core/core_test.go => boilingcore/boilingcore_test.go (99%)
 rename {core => boilingcore}/config.go (97%)
 rename {core => boilingcore}/imports.go (99%)
 rename {core => boilingcore}/imports_test.go (99%)
 rename {core => boilingcore}/output.go (99%)
 rename {core => boilingcore}/output_test.go (98%)
 rename {core => boilingcore}/templates.go (99%)
 rename {core => boilingcore}/templates_test.go (98%)
 rename {core => boilingcore}/text_helpers.go (99%)
 rename {core => boilingcore}/text_helpers_test.go (99%)

diff --git a/core/core.go b/boilingcore/boilingcore.go
similarity index 99%
rename from core/core.go
rename to boilingcore/boilingcore.go
index a650559..f3e9ddb 100644
--- a/core/core.go
+++ b/boilingcore/boilingcore.go
@@ -1,6 +1,6 @@
 // Package sqlboiler has types and methods useful for generating code that
 // acts as a fully dynamic ORM might.
-package core
+package boilingcore
 
 import (
 	"encoding/json"
diff --git a/core/core_test.go b/boilingcore/boilingcore_test.go
similarity index 99%
rename from core/core_test.go
rename to boilingcore/boilingcore_test.go
index fc56d66..f9e7182 100644
--- a/core/core_test.go
+++ b/boilingcore/boilingcore_test.go
@@ -1,4 +1,4 @@
-package core
+package boilingcore
 
 import (
 	"bufio"
diff --git a/core/config.go b/boilingcore/config.go
similarity index 97%
rename from core/config.go
rename to boilingcore/config.go
index a23f6f2..2fa7346 100644
--- a/core/config.go
+++ b/boilingcore/config.go
@@ -1,4 +1,4 @@
-package core
+package boilingcore
 
 // Config for the running of the commands
 type Config struct {
diff --git a/core/imports.go b/boilingcore/imports.go
similarity index 99%
rename from core/imports.go
rename to boilingcore/imports.go
index 97be767..236d16d 100644
--- a/core/imports.go
+++ b/boilingcore/imports.go
@@ -1,4 +1,4 @@
-package core
+package boilingcore
 
 import (
 	"bytes"
diff --git a/core/imports_test.go b/boilingcore/imports_test.go
similarity index 99%
rename from core/imports_test.go
rename to boilingcore/imports_test.go
index 4a919da..43c46e5 100644
--- a/core/imports_test.go
+++ b/boilingcore/imports_test.go
@@ -1,4 +1,4 @@
-package core
+package boilingcore
 
 import (
 	"reflect"
diff --git a/core/output.go b/boilingcore/output.go
similarity index 99%
rename from core/output.go
rename to boilingcore/output.go
index 1ed13c9..baee236 100644
--- a/core/output.go
+++ b/boilingcore/output.go
@@ -1,4 +1,4 @@
-package core
+package boilingcore
 
 import (
 	"bufio"
diff --git a/core/output_test.go b/boilingcore/output_test.go
similarity index 98%
rename from core/output_test.go
rename to boilingcore/output_test.go
index 05e94c1..fa954e3 100644
--- a/core/output_test.go
+++ b/boilingcore/output_test.go
@@ -1,4 +1,4 @@
-package core
+package boilingcore
 
 import (
 	"bytes"
diff --git a/core/templates.go b/boilingcore/templates.go
similarity index 99%
rename from core/templates.go
rename to boilingcore/templates.go
index 2da75b7..9e8695c 100644
--- a/core/templates.go
+++ b/boilingcore/templates.go
@@ -1,4 +1,4 @@
-package core
+package boilingcore
 
 import (
 	"fmt"
diff --git a/core/templates_test.go b/boilingcore/templates_test.go
similarity index 98%
rename from core/templates_test.go
rename to boilingcore/templates_test.go
index 6dea42b..25e4777 100644
--- a/core/templates_test.go
+++ b/boilingcore/templates_test.go
@@ -1,4 +1,4 @@
-package core
+package boilingcore
 
 import (
 	"sort"
diff --git a/core/text_helpers.go b/boilingcore/text_helpers.go
similarity index 99%
rename from core/text_helpers.go
rename to boilingcore/text_helpers.go
index 2df5887..e9577a7 100644
--- a/core/text_helpers.go
+++ b/boilingcore/text_helpers.go
@@ -1,4 +1,4 @@
-package core
+package boilingcore
 
 import (
 	"fmt"
diff --git a/core/text_helpers_test.go b/boilingcore/text_helpers_test.go
similarity index 99%
rename from core/text_helpers_test.go
rename to boilingcore/text_helpers_test.go
index b879fb9..8beed50 100644
--- a/core/text_helpers_test.go
+++ b/boilingcore/text_helpers_test.go
@@ -1,4 +1,4 @@
-package core
+package boilingcore
 
 import (
 	"reflect"
diff --git a/main.go b/main.go
index 738df64..76ae0f8 100644
--- a/main.go
+++ b/main.go
@@ -11,14 +11,14 @@ import (
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 	"github.com/vattle/sqlboiler/bdb/drivers"
-	"github.com/vattle/sqlboiler/core"
+	"github.com/vattle/sqlboiler/boilingcore"
 )
 
 const sqlBoilerVersion = "2.1.5"
 
 var (
-	cmdState  *core.State
-	cmdConfig *core.Config
+	cmdState  *boilingcore.State
+	cmdConfig *boilingcore.Config
 )
 
 func main() {
@@ -123,7 +123,7 @@ func preRun(cmd *cobra.Command, args []string) error {
 
 	driverName := args[0]
 
-	cmdConfig = &core.Config{
+	cmdConfig = &boilingcore.Config{
 		DriverName:       driverName,
 		OutFolder:        viper.GetString("output"),
 		Schema:           viper.GetString("schema"),
@@ -164,7 +164,7 @@ func preRun(cmd *cobra.Command, args []string) error {
 	}
 
 	if driverName == "postgres" {
-		cmdConfig.Postgres = core.PostgresConfig{
+		cmdConfig.Postgres = boilingcore.PostgresConfig{
 			User:    viper.GetString("postgres.user"),
 			Pass:    viper.GetString("postgres.pass"),
 			Host:    viper.GetString("postgres.host"),
@@ -200,7 +200,7 @@ func preRun(cmd *cobra.Command, args []string) error {
 	}
 
 	if driverName == "mysql" {
-		cmdConfig.MySQL = core.MySQLConfig{
+		cmdConfig.MySQL = boilingcore.MySQLConfig{
 			User:    viper.GetString("mysql.user"),
 			Pass:    viper.GetString("mysql.pass"),
 			Host:    viper.GetString("mysql.host"),
@@ -241,7 +241,7 @@ func preRun(cmd *cobra.Command, args []string) error {
 		}
 	}
 
-	cmdState, err = core.New(cmdConfig)
+	cmdState, err = boilingcore.New(cmdConfig)
 	return err
 }
 

From 4506da6b4184e454c3d094eaf79472acfb499869 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Fri, 13 Jan 2017 20:01:00 -0800
Subject: [PATCH 022/179] Change detection hack for broken arrays in viper

- Fix #91
---
 main.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/main.go b/main.go
index 76ae0f8..992860d 100644
--- a/main.go
+++ b/main.go
@@ -140,7 +140,7 @@ func preRun(cmd *cobra.Command, args []string) error {
 	// detect a malformed value coming out of viper.
 	// Once the bug is fixed we'll be able to move this into the init above
 	cmdConfig.BlacklistTables = viper.GetStringSlice("blacklist")
-	if len(cmdConfig.BlacklistTables) == 1 && strings.HasPrefix(cmdConfig.BlacklistTables[0], "[") {
+	if len(cmdConfig.BlacklistTables) == 1 && strings.ContainsRune(cmdConfig.BlacklistTables[0], ',') {
 		cmdConfig.BlacklistTables, err = cmd.PersistentFlags().GetStringSlice("blacklist")
 		if err != nil {
 			return err
@@ -148,7 +148,7 @@ func preRun(cmd *cobra.Command, args []string) error {
 	}
 
 	cmdConfig.WhitelistTables = viper.GetStringSlice("whitelist")
-	if len(cmdConfig.WhitelistTables) == 1 && strings.HasPrefix(cmdConfig.WhitelistTables[0], "[") {
+	if len(cmdConfig.WhitelistTables) == 1 && strings.ContainsRune(cmdConfig.WhitelistTables[0], ',') {
 		cmdConfig.WhitelistTables, err = cmd.PersistentFlags().GetStringSlice("whitelist")
 		if err != nil {
 			return err
@@ -156,7 +156,7 @@ func preRun(cmd *cobra.Command, args []string) error {
 	}
 
 	cmdConfig.Tags = viper.GetStringSlice("tag")
-	if len(cmdConfig.Tags) == 1 && strings.HasPrefix(cmdConfig.Tags[0], "[") {
+	if len(cmdConfig.Tags) == 1 && strings.ContainsRune(cmdConfig.Tags[0], ',') {
 		cmdConfig.Tags, err = cmd.PersistentFlags().GetStringSlice("tag")
 		if err != nil {
 			return err

From faf511a7e67a614b7226db145ac88a0b62041358 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sat, 14 Jan 2017 16:13:32 +1000
Subject: [PATCH 023/179] fix boilingcore package comment

---
 boilingcore/boilingcore.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/boilingcore/boilingcore.go b/boilingcore/boilingcore.go
index f3e9ddb..c5d5519 100644
--- a/boilingcore/boilingcore.go
+++ b/boilingcore/boilingcore.go
@@ -1,4 +1,4 @@
-// Package sqlboiler has types and methods useful for generating code that
+// Package boilingcore has types and methods useful for generating code that
 // acts as a fully dynamic ORM might.
 package boilingcore
 

From cb54ded2077b1f9fb6ff31df8f3a31485f712cfe Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sun, 15 Jan 2017 11:43:58 +1000
Subject: [PATCH 024/179] add sqlboiler logo

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 1479d6c..34e6f2e 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# SQLBoiler
+![sqlboiler logo](http://i.imgur.com/NJtCT7y.png)
 
 [![License](https://img.shields.io/badge/license-BSD-blue.svg)](https://github.com/vattle/sqlboiler/blob/master/LICENSE)
 [![GoDoc](https://godoc.org/github.com/vattle/sqlboiler?status.svg)](https://godoc.org/github.com/vattle/sqlboiler)

From bfba60eaad30f691f1e3b83882b370223fa5416b Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Sun, 15 Jan 2017 21:10:01 -0800
Subject: [PATCH 025/179] Bump version

---
 main.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/main.go b/main.go
index 992860d..3ce0514 100644
--- a/main.go
+++ b/main.go
@@ -14,7 +14,7 @@ import (
 	"github.com/vattle/sqlboiler/boilingcore"
 )
 
-const sqlBoilerVersion = "2.1.5"
+const sqlBoilerVersion = "2.1.7"
 
 var (
 	cmdState  *boilingcore.State

From 761efee9f0ec673fb6c329300ed2114427d4957d Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Sun, 15 Jan 2017 21:21:04 -0800
Subject: [PATCH 026/179] Add ability to replace a template

- This feature remains undocumented because it's not a good idea in most
  cases but it enables us to replace a template. This is especially
  useful when using sqlboiler as a library since testmain
  problematically loads config in it's own magical way, divorced from
  even the way sqlboiler in "normal" mode loads it. This enables
  replacement of that mechanism by replacing it's template.
---
 boilingcore/boilingcore.go | 38 +++++++++++++++++++++++++++++++++++++-
 boilingcore/config.go      |  1 +
 boilingcore/templates.go   | 24 +++++++++++++++++-------
 main.go                    |  9 +++++++++
 4 files changed, 64 insertions(+), 8 deletions(-)

diff --git a/boilingcore/boilingcore.go b/boilingcore/boilingcore.go
index c5d5519..3bd9fdc 100644
--- a/boilingcore/boilingcore.go
+++ b/boilingcore/boilingcore.go
@@ -198,7 +198,43 @@ func (s *State) initTemplates() error {
 			return err
 		}
 
-		s.TestMainTemplate, err = loadTemplate(filepath.Join(basePath, templatesTestMainDirectory), s.Config.DriverName+"_main.tpl")
+		testMain := s.Config.DriverName + "_main.tpl"
+		s.TestMainTemplate, err = loadTemplate(nil, testMain, filepath.Join(basePath, templatesTestMainDirectory, testMain))
+		if err != nil {
+			return err
+		}
+	}
+
+	return s.processReplacements()
+}
+
+// processReplacements loads any replacement templates
+func (s *State) processReplacements() error {
+	for _, replace := range s.Config.Replacements {
+		fmt.Println(replace)
+		splits := strings.Split(replace, ":")
+		if len(splits) != 2 {
+			return errors.Errorf("replace parameters must have 2 arguments, given: %s", replace)
+		}
+
+		toReplace, replaceWith := splits[0], splits[1]
+
+		var err error
+		switch filepath.Dir(toReplace) {
+		case templatesDirectory:
+			_, err = loadTemplate(s.Templates.Template, toReplace, replaceWith)
+		case templatesSingletonDirectory:
+			_, err = loadTemplate(s.SingletonTemplates.Template, toReplace, replaceWith)
+		case templatesTestDirectory:
+			_, err = loadTemplate(s.TestTemplates.Template, toReplace, replaceWith)
+		case templatesSingletonTestDirectory:
+			_, err = loadTemplate(s.SingletonTestTemplates.Template, toReplace, replaceWith)
+		case templatesTestMainDirectory:
+			s.TestMainTemplate, err = loadTemplate(nil, toReplace, replaceWith)
+		default:
+			return errors.Errorf("replace file's directory not part of any known folder: %s", toReplace)
+		}
+
 		if err != nil {
 			return err
 		}
diff --git a/boilingcore/config.go b/boilingcore/config.go
index 2fa7346..0b2f15c 100644
--- a/boilingcore/config.go
+++ b/boilingcore/config.go
@@ -10,6 +10,7 @@ type Config struct {
 	WhitelistTables  []string
 	BlacklistTables  []string
 	Tags             []string
+	Replacements     []string
 	Debug            bool
 	NoTests          bool
 	NoHooks          bool
diff --git a/boilingcore/templates.go b/boilingcore/templates.go
index 9e8695c..32bbe6f 100644
--- a/boilingcore/templates.go
+++ b/boilingcore/templates.go
@@ -2,11 +2,13 @@ package boilingcore
 
 import (
 	"fmt"
+	"io/ioutil"
 	"path/filepath"
 	"sort"
 	"strings"
 	"text/template"
 
+	"github.com/pkg/errors"
 	"github.com/vattle/sqlboiler/bdb"
 	"github.com/vattle/sqlboiler/queries"
 	"github.com/vattle/sqlboiler/strmangle"
@@ -109,16 +111,24 @@ func loadTemplates(dir string) (*templateList, error) {
 	return &templateList{Template: tpl}, err
 }
 
-// loadTemplate loads a single template file.
-func loadTemplate(dir string, filename string) (*template.Template, error) {
-	pattern := filepath.Join(dir, filename)
-	tpl, err := template.New("").Funcs(templateFunctions).ParseFiles(pattern)
-
+// loadTemplate loads a single template, uses tpl as a base template if provided
+// and creates a new base template if not.
+func loadTemplate(tpl *template.Template, name, filename string) (*template.Template, error) {
+	b, err := ioutil.ReadFile(filename)
 	if err != nil {
-		return nil, err
+		return nil, errors.Wrapf(err, "failed reading template file: %s", filename)
 	}
 
-	return tpl.Lookup(filename), err
+	if tpl == nil {
+		tpl = template.New(name)
+	} else {
+		tpl = tpl.New(name)
+	}
+	if tpl, err = tpl.Funcs(templateFunctions).Parse(string(b)); err != nil {
+		return nil, errors.Wrapf(err, "failed to parse template file: %s", filename)
+	}
+
+	return tpl, nil
 }
 
 // set is to stop duplication from named enums, allowing a template loop
diff --git a/main.go b/main.go
index 3ce0514..9666477 100644
--- a/main.go
+++ b/main.go
@@ -79,6 +79,7 @@ func main() {
 	rootCmd.PersistentFlags().StringSliceP("blacklist", "b", nil, "Do not include these tables in your generated package")
 	rootCmd.PersistentFlags().StringSliceP("whitelist", "w", nil, "Only include these tables in your generated package")
 	rootCmd.PersistentFlags().StringSliceP("tag", "t", nil, "Struct tags to be included on your models in addition to json, yaml, toml")
+	rootCmd.PersistentFlags().StringSliceP("replace", "", nil, "Replace templates by directory: relpath/to_file.tpl:relpath/to_replacement.tpl")
 	rootCmd.PersistentFlags().BoolP("debug", "d", false, "Debug mode prints stack traces on error")
 	rootCmd.PersistentFlags().BoolP("no-tests", "", false, "Disable generated go test files")
 	rootCmd.PersistentFlags().BoolP("no-hooks", "", false, "Disable hooks feature for your models")
@@ -163,6 +164,14 @@ func preRun(cmd *cobra.Command, args []string) error {
 		}
 	}
 
+	cmdConfig.Replacements = viper.GetStringSlice("replace")
+	if len(cmdConfig.Replacements) == 1 && strings.ContainsRune(cmdConfig.Replacements[0], ',') {
+		cmdConfig.Replacements, err = cmd.PersistentFlags().GetStringSlice("replace")
+		if err != nil {
+			return err
+		}
+	}
+
 	if driverName == "postgres" {
 		cmdConfig.Postgres = boilingcore.PostgresConfig{
 			User:    viper.GetString("postgres.user"),

From e992e327c2727801cbe050a0df33439ccef083e0 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Tue, 24 Jan 2017 13:31:43 +1000
Subject: [PATCH 027/179] Fix inflection bug for "ss" words (like address)

* Adjust inflect rules
* Bump version to 2.1.8
---
 main.go                           |  2 +-
 strmangle/inflect.go              | 14 ++++++++++++++
 testdata/postgres_test_schema.sql | 11 +++++++++++
 3 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/main.go b/main.go
index 9666477..8202ea7 100644
--- a/main.go
+++ b/main.go
@@ -14,7 +14,7 @@ import (
 	"github.com/vattle/sqlboiler/boilingcore"
 )
 
-const sqlBoilerVersion = "2.1.7"
+const sqlBoilerVersion = "2.1.8"
 
 var (
 	cmdState  *boilingcore.State
diff --git a/strmangle/inflect.go b/strmangle/inflect.go
index 78945b6..6238c39 100644
--- a/strmangle/inflect.go
+++ b/strmangle/inflect.go
@@ -92,6 +92,10 @@ func newBoilRuleset() *inflect.Ruleset {
 	rs.AddPluralExact("oxen", "oxen", true)
 	rs.AddPluralExact("quiz", "quizzes", true)
 	rs.AddSingular("s", "")
+	rs.AddSingular("ss", "ss")
+	rs.AddSingular("as", "as")
+	rs.AddSingular("us", "us")
+	rs.AddSingular("is", "is")
 	rs.AddSingular("news", "news")
 	rs.AddSingular("ta", "tum")
 	rs.AddSingular("ia", "ium")
@@ -184,5 +188,15 @@ func newBoilRuleset() *inflect.Ruleset {
 	rs.AddIrregular("move", "moves")
 	rs.AddIrregular("zombie", "zombies")
 	rs.AddIrregular("cookie", "cookies")
+	rs.AddSingularExact("a", "a", true)
+	rs.AddSingularExact("i", "i", true)
+	rs.AddSingularExact("is", "is", true)
+	rs.AddSingularExact("us", "us", true)
+	rs.AddSingularExact("as", "as", true)
+	rs.AddPluralExact("a", "a", true)
+	rs.AddPluralExact("i", "i", true)
+	rs.AddPluralExact("is", "is", true)
+	rs.AddPluralExact("us", "us", true)
+	rs.AddPluralExact("as", "as", true)
 	return rs
 }
diff --git a/testdata/postgres_test_schema.sql b/testdata/postgres_test_schema.sql
index e0a043c..3e29c74 100644
--- a/testdata/postgres_test_schema.sql
+++ b/testdata/postgres_test_schema.sql
@@ -306,6 +306,17 @@ create table worms (
   foreign key (tiger_id) references tigers (id)
 );
 
+create table addresses (
+  id bytea primary key,
+  name bytea null
+);
+
+create table houses (
+  id bytea primary key,
+  name bytea not null,
+  address_id bytea not null unique,
+  foreign key (address_id) references addresses (id)
+);
 
 create table byte_pilots (
   id   bytea primary key not null,

From c33bb479a13660c848f60d8e51eed4ef74b3c186 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 24 Jan 2017 18:57:45 -0800
Subject: [PATCH 028/179] Fix postgres placeholders for to-many.RemoveX

- Help fix #97
---
 templates/12_relationship_to_many_setops.tpl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/templates/12_relationship_to_many_setops.tpl b/templates/12_relationship_to_many_setops.tpl
index 04c1b97..fee21d3 100644
--- a/templates/12_relationship_to_many_setops.tpl
+++ b/templates/12_relationship_to_many_setops.tpl
@@ -250,7 +250,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}(exec boil.Exec
 	{{if .ToJoinTable -}}
 	query := fmt.Sprintf(
 		"delete from {{.JoinTable | $dot.SchemaTable}} where {{.JoinLocalColumn | $dot.Quotes}} = {{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}} and {{.JoinForeignColumn | $dot.Quotes}} in (%s)",
-		strmangle.Placeholders(dialect.IndexPlaceholders, len(related), 1, 1),
+		strmangle.Placeholders(dialect.IndexPlaceholders, len(related), 2, 1),
 	)
 	values := []interface{}{{"{"}}o.{{$txt.LocalTable.ColumnNameGo}}}
 

From bdb0ef1b7ca3b977b23d66d6e760e8057c0a0835 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 24 Jan 2017 22:43:46 -0800
Subject: [PATCH 029/179] Fix missing tests

- ToMany(Set|Remove)Op tests were not being generated for join tables.
---
 templates_test/singleton/boil_suites_test.tpl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/templates_test/singleton/boil_suites_test.tpl b/templates_test/singleton/boil_suites_test.tpl
index 8723da4..08a5e21 100644
--- a/templates_test/singleton/boil_suites_test.tpl
+++ b/templates_test/singleton/boil_suites_test.tpl
@@ -251,7 +251,7 @@ func TestToManySet(t *testing.T) {
     {{- if $table.IsJoinTable -}}
     {{- else -}}
       {{- range $table.ToManyRelationships -}}
-        {{- if not .ForeignColumnNullable -}}
+        {{- if not (or .ForeignColumnNullable .ToJoinTable)}}
         {{- else -}}
           {{- $txt := txtsFromToMany $dot.Tables $table . -}}
     t.Run("{{$txt.LocalTable.NameGo}}To{{$txt.Function.Name}}", test{{$txt.LocalTable.NameGo}}ToManySetOp{{$txt.Function.Name}})
@@ -268,7 +268,7 @@ func TestToManyRemove(t *testing.T) {
     {{- if $table.IsJoinTable -}}
     {{- else -}}
       {{- range $table.ToManyRelationships -}}
-        {{- if not .ForeignColumnNullable -}}
+        {{- if not (or .ForeignColumnNullable .ToJoinTable)}}
         {{- else -}}
           {{- $txt := txtsFromToMany $dot.Tables $table . -}}
     t.Run("{{$txt.LocalTable.NameGo}}To{{$txt.Function.Name}}", test{{$txt.LocalTable.NameGo}}ToManyRemoveOp{{$txt.Function.Name}})

From 936df65ebc37b11be324906688bf4fe5481b0922 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 24 Jan 2017 22:45:20 -0800
Subject: [PATCH 030/179] Fix ToManyRemoveOp

- This would generate a bad query when run, also the test was failing
  for this same reason and once enabled it was trivial to fix.
---
 templates/12_relationship_to_many_setops.tpl | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/templates/12_relationship_to_many_setops.tpl b/templates/12_relationship_to_many_setops.tpl
index fee21d3..bc5e220 100644
--- a/templates/12_relationship_to_many_setops.tpl
+++ b/templates/12_relationship_to_many_setops.tpl
@@ -253,6 +253,9 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}(exec boil.Exec
 		strmangle.Placeholders(dialect.IndexPlaceholders, len(related), 2, 1),
 	)
 	values := []interface{}{{"{"}}o.{{$txt.LocalTable.ColumnNameGo}}}
+	for _, rel := range related {
+		values = append(values, rel.{{$txt.ForeignTable.ColumnNameGo}})
+	}
 
 	if boil.DebugMode {
 		fmt.Fprintln(boil.DebugWriter, query)

From d79f816cc19af0331f759bc364b61ec34b436c1a Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 24 Jan 2017 23:03:59 -0800
Subject: [PATCH 031/179] Fix test failure

- Optimistic code removed. It wasn't possible to test for this condition
  ever.
---
 templates_test/relationship_to_many_setops.tpl | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/templates_test/relationship_to_many_setops.tpl b/templates_test/relationship_to_many_setops.tpl
index 01471f4..f66ba8a 100644
--- a/templates_test/relationship_to_many_setops.tpl
+++ b/templates_test/relationship_to_many_setops.tpl
@@ -159,12 +159,16 @@ func test{{$txt.LocalTable.NameGo}}ToManySetOp{{$txt.Function.Name}}(t *testing.
 
 	{{- if .ToJoinTable}}
 
-	if len(b.R.{{$txt.Function.ForeignName}}) != 0 {
-		t.Error("relationship was not removed properly from the slice")
-	}
-	if len(c.R.{{$txt.Function.ForeignName}}) != 0 {
-		t.Error("relationship was not removed properly from the slice")
-	}
+	// The following checks cannot be implemented since we have no handle
+	// to these when we call Set(). Leaving them here as wishful thinking
+	// and to let people know there's dragons.
+	//
+	// if len(b.R.{{$txt.Function.ForeignName}}) != 0 {
+	// 	t.Error("relationship was not removed properly from the slice")
+	// }
+	// if len(c.R.{{$txt.Function.ForeignName}}) != 0 {
+	// 	t.Error("relationship was not removed properly from the slice")
+	// }
 	if d.R.{{$txt.Function.ForeignName}}[0] != &a {
 		t.Error("relationship was not added properly to the slice")
 	}

From c02a2f0c2074e8f68b5096291e6d82ff9547bd90 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 24 Jan 2017 23:04:59 -0800
Subject: [PATCH 032/179] Fix null dereference

---
 templates/12_relationship_to_many_setops.tpl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/templates/12_relationship_to_many_setops.tpl b/templates/12_relationship_to_many_setops.tpl
index bc5e220..06159ee 100644
--- a/templates/12_relationship_to_many_setops.tpl
+++ b/templates/12_relationship_to_many_setops.tpl
@@ -195,7 +195,9 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 
 	{{if .ToJoinTable -}}
 	remove{{$txt.Function.Name}}From{{$txt.Function.ForeignName}}Slice(o, related)
-	o.R.{{$txt.Function.Name}} = nil
+	if o.R != nil {
+		o.R.{{$txt.Function.Name}} = nil
+	}
 	{{else -}}
 	if o.R != nil {
 		for _, rel := range o.R.{{$txt.Function.Name}} {

From ec28cb4148c63f305f4dee350a4b63604ceb1427 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Thu, 26 Jan 2017 20:41:30 -0800
Subject: [PATCH 033/179] Add no-edit disclaimer to all generated files

- As discussed in #96
---
 boilingcore/output.go | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/boilingcore/output.go b/boilingcore/output.go
index baee236..ffbde94 100644
--- a/boilingcore/output.go
+++ b/boilingcore/output.go
@@ -14,6 +14,12 @@ import (
 	"github.com/pkg/errors"
 )
 
+var noEditDisclaimer = []byte(`// This file is generated by SQLBoiler (https://github.com/vattle/sqlboiler)
+// and is meant to be re-generated in place and/or deleted at any time.
+// DO NOT EDIT
+
+`)
+
 var (
 	// templateByteBuffer is re-used by all template construction to avoid
 	// allocating more memory than is needed. This will later be a problem for
@@ -103,6 +109,7 @@ func executeTemplates(e executeTemplateData) error {
 		imps = combineTypeImports(imps, importsBasedOnType, e.data.Table.Columns)
 	}
 
+	writeFileDisclaimer(out)
 	writePackageName(out, e.state.Config.PkgName)
 	writeImports(out, imps)
 
@@ -138,6 +145,7 @@ func executeSingletonTemplates(e executeTemplateData) error {
 			thirdParty: e.importNamedSet[fName].thirdParty,
 		}
 
+		writeFileDisclaimer(out)
 		writePackageName(out, e.state.Config.PkgName)
 		writeImports(out, imps)
 
@@ -165,6 +173,7 @@ func generateTestMainOutput(state *State, data *templateData) error {
 	imps.standard = defaultTestMainImports[state.Config.DriverName].standard
 	imps.thirdParty = defaultTestMainImports[state.Config.DriverName].thirdParty
 
+	writeFileDisclaimer(out)
 	writePackageName(out, state.Config.PkgName)
 	writeImports(out, imps)
 
@@ -179,6 +188,12 @@ func generateTestMainOutput(state *State, data *templateData) error {
 	return nil
 }
 
+// writeFileDisclaimer writes the disclaimer at the top with a trailing
+// newline so the package name doesn't get attached to it.
+func writeFileDisclaimer(out *bytes.Buffer) {
+	_, _ = out.Write(noEditDisclaimer)
+}
+
 // writePackageName writes the package name correctly, ignores errors
 // since it's to the concrete buffer type which produces none
 func writePackageName(out *bytes.Buffer, pkgName string) {

From 671e1d7ae9064c15a318dade0d5cf27322a37376 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Thu, 26 Jan 2017 20:42:14 -0800
Subject: [PATCH 034/179] Add --wipe flag to rm the output dir pre-generate

- As discussed in #96
---
 boilingcore/boilingcore.go | 6 ++++++
 boilingcore/config.go      | 1 +
 main.go                    | 2 ++
 3 files changed, 9 insertions(+)

diff --git a/boilingcore/boilingcore.go b/boilingcore/boilingcore.go
index 3bd9fdc..1030ddb 100644
--- a/boilingcore/boilingcore.go
+++ b/boilingcore/boilingcore.go
@@ -333,6 +333,12 @@ func (s *State) initTags(tags []string) error {
 
 // initOutFolder creates the folder that will hold the generated output.
 func (s *State) initOutFolder() error {
+	if s.Config.Wipe {
+		if err := os.RemoveAll(s.Config.OutFolder); err != nil {
+			return err
+		}
+	}
+
 	return os.MkdirAll(s.Config.OutFolder, os.ModePerm)
 }
 
diff --git a/boilingcore/config.go b/boilingcore/config.go
index 0b2f15c..62da693 100644
--- a/boilingcore/config.go
+++ b/boilingcore/config.go
@@ -15,6 +15,7 @@ type Config struct {
 	NoTests          bool
 	NoHooks          bool
 	NoAutoTimestamps bool
+	Wipe             bool
 
 	Postgres PostgresConfig
 	MySQL    MySQLConfig
diff --git a/main.go b/main.go
index 8202ea7..098c9bd 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("wipe", "", false, "Delete the output folder (rm -rf) before generation to ensure sanity")
 
 	viper.SetDefault("postgres.sslmode", "require")
 	viper.SetDefault("postgres.port", "5432")
@@ -134,6 +135,7 @@ func preRun(cmd *cobra.Command, args []string) error {
 		NoTests:          viper.GetBool("no-tests"),
 		NoHooks:          viper.GetBool("no-hooks"),
 		NoAutoTimestamps: viper.GetBool("no-auto-timestamps"),
+		Wipe:             viper.GetBool("wipe"),
 	}
 
 	// BUG: https://github.com/spf13/viper/issues/200

From 0221da2491f4c4647a32c38ea53c5ebc2de93639 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Thu, 26 Jan 2017 21:16:22 -0800
Subject: [PATCH 035/179] Document: regeneration, extensions, --wipe flag

- As discussed in #96
---
 README.md | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 112 insertions(+)

diff --git a/README.md b/README.md
index 34e6f2e..b2d8ae1 100644
--- a/README.md
+++ b/README.md
@@ -48,6 +48,8 @@ Table of Contents
         * [Download](#download)
         * [Configuration](#configuration)
         * [Initial Generation](#initial-generation)
+        * [Regeneration](#regeneration)
+        * [Extending Generated Models](#extending-generated-models)
     * [Diagnosing Problems](#diagnosing-problems)
     * [Features &amp; Examples](#features--examples)
       * [Automatic CreatedAt/UpdatedAt](#automatic-createdatupdatedat)
@@ -317,6 +319,116 @@ sqlboiler -b goose_migrations postgres
 go test ./models
 ```
 
+You can use `go generate` for SQLBoiler if you want to to make it easy to
+run the command.
+
+It's important to not modify anything in the output folder, which brings us to
+the next topic: regeneration.
+
+#### Regeneration
+
+When regenerating the models it's recommended that you completely delete the
+generated directory in a build script or use the `--wipe` flag in SQLBoiler.
+The reasons for this are that sqlboiler doesn't try to diff your files in any
+smart way, it simply writes the files it's going to write whether they're there
+or not and doesn't delete any files that were added by you or previous runs of
+SQLBoiler. In the best case this can cause compilation errors, in the worst case
+this may leave extraneous and unusable code that was generated against tables
+that are no longer in the database.
+
+The bottom line is that this tool should always produce the same result from
+the same source. And the intention is to always regenerate from a pure state.
+The only reason the `--wipe` flag isn't defaulted to on is because we don't
+like programs that `rm -rf` things on the filesystem without being asked to.
+
+#### Extending generated models
+
+There will probably come a time when you want to extend the generated models
+with some kinds of helper functions. A general guideline is to put your
+extension functions into a separate package so that your functions aren't
+accidentally deleted when regenerating. Past that there are 3 main ways to
+extend the models, the first way is the most desirable:
+
+**Method 1: Simple Functions**
+
+```go
+// Package modext is for SQLBoiler helper methods
+package modext
+
+// UserFirstTimeSetup is an extension of the user model.
+func UserFirstTimeSetup(db *sql.DB, u *models.User) error { ... }
+```
+
+Code organization is accomplished by using multiple files, and everything
+is passed as a parameter so these kinds of methods are very easy to test.
+
+Calling code is also very straightforward:
+
+```go
+user, err := Users(db).One()
+// elided error check
+
+err = modext.UserFirstTimeSetup(db, user)
+// elided error check
+```
+
+**Method 2: Empty struct methods**
+
+The above is the best way to code extensions for SQLBoiler, however there may
+be times when the number of methods grows too large and code completion is
+not as helpful anymore. In these cases you may consider structuring the code
+like this:
+
+```go
+// Package modext is for SQLBoiler helper methods
+package modext
+
+type users struct {}
+
+var Users = users{}
+
+// FirstTimeSetup is an extension of the user model.
+func (u users) FirstTimeSetup(db *sql.DB, u *models.User) error { ... }
+```
+
+Calling code then looks a little bit different:
+
+```go
+user, err := Users(db).One()
+// elided error check
+
+err = modext.Users.FirstTimeSetup(db, user)
+// elided error check
+```
+
+This is almost identical to the method above, but gives slight amounts more
+organization at virtually no cost at runtime. It is however not as desirable
+as the first method since it does have some runtime cost and doesn't offer that
+much benefit over it.
+
+**Method 3: Embedding**
+
+This pattern is not for the feint of heart, what it provides in benefits it
+more than makes up for in downsides. It's possible to embed the SQLBoiler
+structs inside your own to enhance them. However it's subject to easy breakages
+and a dependency on these additional objects. It can also introduce
+inconsistencies as some objects may have no extended functionality and therefore
+have no reason to be embedded so you either have to have a struct for each
+generated struct even if it's empty, or have inconsistencies, some places where
+you use the enhanced model, and some where you do not.
+
+```go
+user, err := Users(db).One()
+// elided error check
+
+enhUser := modext.User{user}
+err = ehnUser.FirstTimeSetup(db)
+// elided error check
+```
+
+I don't recommend this pattern, but included it so that people know it's an
+option and also know the problems with it.
+
 ## Diagnosing Problems
 
 The most common causes of problems and panics are:

From 59c238539ddc3e0ee964e24f0f30910875c88334 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Thu, 26 Jan 2017 22:06:47 -0800
Subject: [PATCH 036/179] Attach all eagerly loaded models in to-one

- The problem here is that due to the nature of the relationship and the
  way the loop was set up it was possible to miss some relationships:

A _ C
 \_ D

B _ E
 \_ F

Since we looped over A and B and did a break when we found something to
attach it to (in this example A would find C) it would break. What we
should be looping through is CDEF and finding a home for each one.

Did the same change in to_one though it doesn't matter since it's
one-to-one.

to-many is untouched because it's already looping over CDEF and finding
a home for it because the relationship is reversed.

- Fix #98
---
 templates/07_relationship_to_one_eager.tpl     | 10 +++++++---
 templates/08_relationship_one_to_one_eager.tpl | 10 +++++++---
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/templates/07_relationship_to_one_eager.tpl b/templates/07_relationship_to_one_eager.tpl
index 43392f0..4af84ca 100644
--- a/templates/07_relationship_to_one_eager.tpl
+++ b/templates/07_relationship_to_one_eager.tpl
@@ -65,13 +65,17 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 	}
 	{{- end}}
 
-	if singular && len(resultSlice) != 0 {
+	if len(resultSlice) == 0 {
+		return nil
+	}
+
+	if singular {
 		object.R.{{$txt.Function.Name}} = resultSlice[0]
 		return nil
 	}
 
-	for _, foreign := range resultSlice {
-		for _, local := range slice {
+	for _, local := range slice {
+		for _, foreign := range resultSlice {
 			{{if $txt.Function.UsesBytes -}}
 			if 0 == bytes.Compare(local.{{$txt.Function.LocalAssignment}}, foreign.{{$txt.Function.ForeignAssignment}}) {
 			{{else -}}
diff --git a/templates/08_relationship_one_to_one_eager.tpl b/templates/08_relationship_one_to_one_eager.tpl
index 6603d55..7363b69 100644
--- a/templates/08_relationship_one_to_one_eager.tpl
+++ b/templates/08_relationship_one_to_one_eager.tpl
@@ -65,13 +65,17 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 	}
 	{{- end}}
 
-	if singular && len(resultSlice) != 0 {
+	if len(resultSlice) == 0 {
+		return nil
+	}
+
+	if singular {
 		object.R.{{$txt.Function.Name}} = resultSlice[0]
 		return nil
 	}
 
-	for _, foreign := range resultSlice {
-		for _, local := range slice {
+	for _, local := range slice {
+		for _, foreign := range resultSlice {
 			{{if $txt.Function.UsesBytes -}}
 			if 0 == bytes.Compare(local.{{$txt.Function.LocalAssignment}}, foreign.{{$txt.Function.ForeignAssignment}}) {
 			{{else -}}

From 10ee452032f9f21df31e18f4727feb6edba94449 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sat, 4 Feb 2017 15:51:07 +1000
Subject: [PATCH 037/179] Hide replace flag from help output

* Replace flag is a "not recommended for use" flag, and is mainly
present to be used with software that is using sqlboiler as a library,
such as abcweb
---
 main.go | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/main.go b/main.go
index 098c9bd..e8d2969 100644
--- a/main.go
+++ b/main.go
@@ -14,7 +14,7 @@ import (
 	"github.com/vattle/sqlboiler/boilingcore"
 )
 
-const sqlBoilerVersion = "2.1.8"
+const sqlBoilerVersion = "2.1.9"
 
 var (
 	cmdState  *boilingcore.State
@@ -88,6 +88,9 @@ func main() {
 	rootCmd.PersistentFlags().BoolP("tinyint-as-bool", "", false, "Map MySQL tinyint(1) in Go to bool instead of int8")
 	rootCmd.PersistentFlags().BoolP("wipe", "", false, "Delete the output folder (rm -rf) before generation to ensure sanity")
 
+	// hide flags not recommended for use
+	rootCmd.PersistentFlags().MarkHidden("replace")
+
 	viper.SetDefault("postgres.sslmode", "require")
 	viper.SetDefault("postgres.port", "5432")
 	viper.SetDefault("mysql.sslmode", "true")

From acaf94ef5fb8772070ef890487922f04e7753c25 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sat, 4 Feb 2017 23:22:39 +1000
Subject: [PATCH 038/179] Remove println that should not be present

---
 boilingcore/boilingcore.go | 1 -
 1 file changed, 1 deletion(-)

diff --git a/boilingcore/boilingcore.go b/boilingcore/boilingcore.go
index 1030ddb..cf8eb95 100644
--- a/boilingcore/boilingcore.go
+++ b/boilingcore/boilingcore.go
@@ -211,7 +211,6 @@ func (s *State) initTemplates() error {
 // processReplacements loads any replacement templates
 func (s *State) processReplacements() error {
 	for _, replace := range s.Config.Replacements {
-		fmt.Println(replace)
 		splits := strings.Split(replace, ":")
 		if len(splits) != 2 {
 			return errors.Errorf("replace parameters must have 2 arguments, given: %s", replace)

From 60814eed1fb5dbefeb5e1fb2579ee75fa35c9f0e Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sun, 5 Feb 2017 02:24:20 +1000
Subject: [PATCH 039/179] Fix replace feature

---
 boilingcore/boilingcore.go | 16 +++++++++-------
 boilingcore/templates.go   | 35 +++++++++++++++++++++++------------
 2 files changed, 32 insertions(+), 19 deletions(-)

diff --git a/boilingcore/boilingcore.go b/boilingcore/boilingcore.go
index cf8eb95..a86e403 100644
--- a/boilingcore/boilingcore.go
+++ b/boilingcore/boilingcore.go
@@ -198,8 +198,7 @@ func (s *State) initTemplates() error {
 			return err
 		}
 
-		testMain := s.Config.DriverName + "_main.tpl"
-		s.TestMainTemplate, err = loadTemplate(nil, testMain, filepath.Join(basePath, templatesTestMainDirectory, testMain))
+		s.TestMainTemplate, err = loadTemplate(filepath.Join(basePath, templatesTestMainDirectory), s.Config.DriverName+"_main.tpl")
 		if err != nil {
 			return err
 		}
@@ -218,18 +217,21 @@ func (s *State) processReplacements() error {
 
 		toReplace, replaceWith := splits[0], splits[1]
 
+		toReplaceSplit := strings.Split(toReplace, string(filepath.Separator))
+		fileName := toReplaceSplit[len(toReplaceSplit)-1]
+
 		var err error
 		switch filepath.Dir(toReplace) {
 		case templatesDirectory:
-			_, err = loadTemplate(s.Templates.Template, toReplace, replaceWith)
+			err = replaceTemplate(s.Templates.Template, fileName, replaceWith)
 		case templatesSingletonDirectory:
-			_, err = loadTemplate(s.SingletonTemplates.Template, toReplace, replaceWith)
+			err = replaceTemplate(s.SingletonTemplates.Template, fileName, replaceWith)
 		case templatesTestDirectory:
-			_, err = loadTemplate(s.TestTemplates.Template, toReplace, replaceWith)
+			err = replaceTemplate(s.TestTemplates.Template, fileName, replaceWith)
 		case templatesSingletonTestDirectory:
-			_, err = loadTemplate(s.SingletonTestTemplates.Template, toReplace, replaceWith)
+			err = replaceTemplate(s.SingletonTestTemplates.Template, fileName, replaceWith)
 		case templatesTestMainDirectory:
-			s.TestMainTemplate, err = loadTemplate(nil, toReplace, replaceWith)
+			err = replaceTemplate(s.TestMainTemplate, fileName, replaceWith)
 		default:
 			return errors.Errorf("replace file's directory not part of any known folder: %s", toReplace)
 		}
diff --git a/boilingcore/templates.go b/boilingcore/templates.go
index 32bbe6f..13f4142 100644
--- a/boilingcore/templates.go
+++ b/boilingcore/templates.go
@@ -111,24 +111,35 @@ func loadTemplates(dir string) (*templateList, error) {
 	return &templateList{Template: tpl}, err
 }
 
-// loadTemplate loads a single template, uses tpl as a base template if provided
-// and creates a new base template if not.
-func loadTemplate(tpl *template.Template, name, filename string) (*template.Template, error) {
+// loadTemplate loads a single template file
+func loadTemplate(dir string, filename string) (*template.Template, error) {
+	pattern := filepath.Join(dir, filename)
+	tpl, err := template.New("").Funcs(templateFunctions).ParseFiles(pattern)
+
+	if err != nil {
+		return nil, err
+	}
+
+	return tpl.Lookup(filename), err
+}
+
+// replaceTemplate finds the template matching with name and replaces its
+// contents with the contents of the template located at filename
+func replaceTemplate(tpl *template.Template, name, filename string) error {
+	if tpl == nil {
+		return fmt.Errorf("template for %s is nil", name)
+	}
+
 	b, err := ioutil.ReadFile(filename)
 	if err != nil {
-		return nil, errors.Wrapf(err, "failed reading template file: %s", filename)
+		return errors.Wrapf(err, "failed reading template file: %s", filename)
 	}
 
-	if tpl == nil {
-		tpl = template.New(name)
-	} else {
-		tpl = tpl.New(name)
-	}
-	if tpl, err = tpl.Funcs(templateFunctions).Parse(string(b)); err != nil {
-		return nil, errors.Wrapf(err, "failed to parse template file: %s", filename)
+	if tpl, err = tpl.New(name).Funcs(templateFunctions).Parse(string(b)); err != nil {
+		return errors.Wrapf(err, "failed to parse template file: %s", filename)
 	}
 
-	return tpl, nil
+	return nil
 }
 
 // set is to stop duplication from named enums, allowing a template loop

From e70ed0d070bf860b052868600551738f2b7c92a7 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sun, 5 Feb 2017 02:27:55 +1000
Subject: [PATCH 040/179] Bump version

---
 main.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/main.go b/main.go
index e8d2969..d601d0c 100644
--- a/main.go
+++ b/main.go
@@ -14,7 +14,7 @@ import (
 	"github.com/vattle/sqlboiler/boilingcore"
 )
 
-const sqlBoilerVersion = "2.1.9"
+const sqlBoilerVersion = "2.1.10"
 
 var (
 	cmdState  *boilingcore.State

From dea061f571ea9a575683c18b7ebf1e72f23d8b09 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sun, 5 Feb 2017 16:45:41 +1000
Subject: [PATCH 041/179] Use Base and Stat instead of os.Seperator split

* Validates we're using filenames and ensures compatibility with all filesystems
---
 boilingcore/boilingcore.go | 30 ++++++++++++++++++++++--------
 1 file changed, 22 insertions(+), 8 deletions(-)

diff --git a/boilingcore/boilingcore.go b/boilingcore/boilingcore.go
index a86e403..e2ba606 100644
--- a/boilingcore/boilingcore.go
+++ b/boilingcore/boilingcore.go
@@ -215,23 +215,37 @@ func (s *State) processReplacements() error {
 			return errors.Errorf("replace parameters must have 2 arguments, given: %s", replace)
 		}
 
+		var toReplaceFname string
 		toReplace, replaceWith := splits[0], splits[1]
 
-		toReplaceSplit := strings.Split(toReplace, string(filepath.Separator))
-		fileName := toReplaceSplit[len(toReplaceSplit)-1]
+		inf, err := os.Stat(toReplace)
+		if err != nil {
+			return errors.Errorf("cannot stat %q", toReplace)
+		}
+		if inf.IsDir() {
+			return errors.Errorf("replace argument must be a path to a file not a dir: %q", toReplace)
+		}
+		toReplaceFname = inf.Name()
+
+		inf, err = os.Stat(replaceWith)
+		if err != nil {
+			return errors.Errorf("cannot stat %q", replaceWith)
+		}
+		if inf.IsDir() {
+			return errors.Errorf("replace argument must be a path to a file not a dir: %q", replaceWith)
+		}
 
-		var err error
 		switch filepath.Dir(toReplace) {
 		case templatesDirectory:
-			err = replaceTemplate(s.Templates.Template, fileName, replaceWith)
+			err = replaceTemplate(s.Templates.Template, toReplaceFname, replaceWith)
 		case templatesSingletonDirectory:
-			err = replaceTemplate(s.SingletonTemplates.Template, fileName, replaceWith)
+			err = replaceTemplate(s.SingletonTemplates.Template, toReplaceFname, replaceWith)
 		case templatesTestDirectory:
-			err = replaceTemplate(s.TestTemplates.Template, fileName, replaceWith)
+			err = replaceTemplate(s.TestTemplates.Template, toReplaceFname, replaceWith)
 		case templatesSingletonTestDirectory:
-			err = replaceTemplate(s.SingletonTestTemplates.Template, fileName, replaceWith)
+			err = replaceTemplate(s.SingletonTestTemplates.Template, toReplaceFname, replaceWith)
 		case templatesTestMainDirectory:
-			err = replaceTemplate(s.TestMainTemplate, fileName, replaceWith)
+			err = replaceTemplate(s.TestMainTemplate, toReplaceFname, replaceWith)
 		default:
 			return errors.Errorf("replace file's directory not part of any known folder: %s", toReplace)
 		}

From e2c53aa3128c69d197aec785a22126c63375f039 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sun, 5 Feb 2017 20:17:11 +1000
Subject: [PATCH 042/179] Add imports library functionality

---
 boilingcore/boilingcore.go  |   4 +
 boilingcore/imports.go      | 465 +++++++++++++++++++++---------------
 boilingcore/imports_test.go | 177 +++++++++++++-
 boilingcore/output.go       |  14 +-
 4 files changed, 464 insertions(+), 196 deletions(-)

diff --git a/boilingcore/boilingcore.go b/boilingcore/boilingcore.go
index e2ba606..e396994 100644
--- a/boilingcore/boilingcore.go
+++ b/boilingcore/boilingcore.go
@@ -43,6 +43,8 @@ type State struct {
 	SingletonTestTemplates *templateList
 
 	TestMainTemplate *template.Template
+
+	Importer importer
 }
 
 // New creates a new state based off of the config
@@ -89,6 +91,8 @@ func New(config *Config) (*State, error) {
 		return nil, errors.Wrap(err, "unable to initialize struct tags")
 	}
 
+	s.Importer = newImporter()
+
 	return s, nil
 }
 
diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index 236d16d..ec2752e 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -141,211 +141,302 @@ func removeDuplicates(dedup []string) []string {
 	return dedup
 }
 
-var defaultTemplateImports = imports{
-	standard: importList{
-		`"bytes"`,
-		`"database/sql"`,
-		`"fmt"`,
-		`"reflect"`,
-		`"strings"`,
-		`"sync"`,
-		`"time"`,
-	},
-	thirdParty: importList{
-		`"github.com/pkg/errors"`,
-		`"github.com/vattle/sqlboiler/boil"`,
-		`"github.com/vattle/sqlboiler/queries"`,
-		`"github.com/vattle/sqlboiler/queries/qm"`,
-		`"github.com/vattle/sqlboiler/strmangle"`,
-	},
+type mapImports map[string]imports
+
+type importer struct {
+	standard     imports
+	testStandard imports
+
+	singleton     mapImports
+	testSingleton mapImports
+
+	testMain mapImports
+
+	basedOnType mapImports
 }
 
-var defaultSingletonTemplateImports = map[string]imports{
-	"boil_queries": {
-		thirdParty: importList{
-			`"github.com/vattle/sqlboiler/boil"`,
-			`"github.com/vattle/sqlboiler/queries"`,
-			`"github.com/vattle/sqlboiler/queries/qm"`,
-		},
-	},
-	"boil_types": {
-		thirdParty: importList{
-			`"github.com/pkg/errors"`,
-			`"github.com/vattle/sqlboiler/strmangle"`,
-		},
-	},
-}
+// newImporter returns an importer struct with default import values
+func newImporter() importer {
+	var imp importer
 
-var defaultTestTemplateImports = imports{
-	standard: importList{
-		`"bytes"`,
-		`"reflect"`,
-		`"testing"`,
-	},
-	thirdParty: importList{
-		`"github.com/vattle/sqlboiler/boil"`,
-		`"github.com/vattle/sqlboiler/randomize"`,
-		`"github.com/vattle/sqlboiler/strmangle"`,
-	},
-}
-
-var defaultSingletonTestTemplateImports = map[string]imports{
-	"boil_main_test": {
+	imp.standard = imports{
 		standard: importList{
+			`"bytes"`,
 			`"database/sql"`,
-			`"flag"`,
 			`"fmt"`,
-			`"math/rand"`,
-			`"os"`,
-			`"path/filepath"`,
-			`"testing"`,
+			`"reflect"`,
+			`"strings"`,
+			`"sync"`,
 			`"time"`,
 		},
 		thirdParty: importList{
-			`"github.com/kat-co/vala"`,
 			`"github.com/pkg/errors"`,
-			`"github.com/spf13/viper"`,
 			`"github.com/vattle/sqlboiler/boil"`,
+			`"github.com/vattle/sqlboiler/queries"`,
+			`"github.com/vattle/sqlboiler/queries/qm"`,
+			`"github.com/vattle/sqlboiler/strmangle"`,
 		},
-	},
-	"boil_queries_test": {
+	}
+
+	imp.singleton = mapImports{
+		"boil_queries": {
+			thirdParty: importList{
+				`"github.com/vattle/sqlboiler/boil"`,
+				`"github.com/vattle/sqlboiler/queries"`,
+				`"github.com/vattle/sqlboiler/queries/qm"`,
+			},
+		},
+		"boil_types": {
+			thirdParty: importList{
+				`"github.com/pkg/errors"`,
+				`"github.com/vattle/sqlboiler/strmangle"`,
+			},
+		},
+	}
+
+	imp.testStandard = imports{
 		standard: importList{
 			`"bytes"`,
-			`"fmt"`,
-			`"io"`,
-			`"io/ioutil"`,
-			`"math/rand"`,
-			`"regexp"`,
-		},
-		thirdParty: importList{
-			`"github.com/vattle/sqlboiler/boil"`,
-		},
-	},
-	"boil_suites_test": {
-		standard: importList{
+			`"reflect"`,
 			`"testing"`,
 		},
-	},
+		thirdParty: importList{
+			`"github.com/vattle/sqlboiler/boil"`,
+			`"github.com/vattle/sqlboiler/randomize"`,
+			`"github.com/vattle/sqlboiler/strmangle"`,
+		},
+	}
+
+	imp.testSingleton = mapImports{
+		"boil_main_test": {
+			standard: importList{
+				`"database/sql"`,
+				`"flag"`,
+				`"fmt"`,
+				`"math/rand"`,
+				`"os"`,
+				`"path/filepath"`,
+				`"testing"`,
+				`"time"`,
+			},
+			thirdParty: importList{
+				`"github.com/kat-co/vala"`,
+				`"github.com/pkg/errors"`,
+				`"github.com/spf13/viper"`,
+				`"github.com/vattle/sqlboiler/boil"`,
+			},
+		},
+		"boil_queries_test": {
+			standard: importList{
+				`"bytes"`,
+				`"fmt"`,
+				`"io"`,
+				`"io/ioutil"`,
+				`"math/rand"`,
+				`"regexp"`,
+			},
+			thirdParty: importList{
+				`"github.com/vattle/sqlboiler/boil"`,
+			},
+		},
+		"boil_suites_test": {
+			standard: importList{
+				`"testing"`,
+			},
+		},
+	}
+
+	imp.testMain = mapImports{
+		"postgres": {
+			standard: importList{
+				`"bytes"`,
+				`"database/sql"`,
+				`"fmt"`,
+				`"io"`,
+				`"io/ioutil"`,
+				`"os"`,
+				`"os/exec"`,
+				`"strings"`,
+			},
+			thirdParty: importList{
+				`"github.com/pkg/errors"`,
+				`"github.com/spf13/viper"`,
+				`"github.com/vattle/sqlboiler/bdb/drivers"`,
+				`"github.com/vattle/sqlboiler/randomize"`,
+				`_ "github.com/lib/pq"`,
+			},
+		},
+		"mysql": {
+			standard: importList{
+				`"bytes"`,
+				`"database/sql"`,
+				`"fmt"`,
+				`"io"`,
+				`"io/ioutil"`,
+				`"os"`,
+				`"os/exec"`,
+				`"strings"`,
+			},
+			thirdParty: importList{
+				`"github.com/pkg/errors"`,
+				`"github.com/spf13/viper"`,
+				`"github.com/vattle/sqlboiler/bdb/drivers"`,
+				`"github.com/vattle/sqlboiler/randomize"`,
+				`_ "github.com/go-sql-driver/mysql"`,
+			},
+		},
+	}
+
+	// basedOnType imports are only included in the template output if the
+	// database requires one of the following special types. Check
+	// TranslateColumnType to see the type assignments.
+	imp.basedOnType = mapImports{
+		"null.Float32": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Float64": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Int": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Int8": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Int16": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Int32": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Int64": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Uint": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Uint8": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Uint16": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Uint32": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Uint64": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.String": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Bool": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Time": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.JSON": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"null.Bytes": {
+			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+		},
+		"time.Time": {
+			standard: importList{`"time"`},
+		},
+		"types.JSON": {
+			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+		},
+		"types.BytesArray": {
+			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+		},
+		"types.Int64Array": {
+			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+		},
+		"types.Float64Array": {
+			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+		},
+		"types.BoolArray": {
+			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+		},
+		"types.StringArray": {
+			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+		},
+		"types.Hstore": {
+			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+		},
+	}
+
+	return imp
 }
 
-var defaultTestMainImports = map[string]imports{
-	"postgres": {
-		standard: importList{
-			`"bytes"`,
-			`"database/sql"`,
-			`"fmt"`,
-			`"io"`,
-			`"io/ioutil"`,
-			`"os"`,
-			`"os/exec"`,
-			`"strings"`,
-		},
-		thirdParty: importList{
-			`"github.com/pkg/errors"`,
-			`"github.com/spf13/viper"`,
-			`"github.com/vattle/sqlboiler/bdb/drivers"`,
-			`"github.com/vattle/sqlboiler/randomize"`,
-			`_ "github.com/lib/pq"`,
-		},
-	},
-	"mysql": {
-		standard: importList{
-			`"bytes"`,
-			`"database/sql"`,
-			`"fmt"`,
-			`"io"`,
-			`"io/ioutil"`,
-			`"os"`,
-			`"os/exec"`,
-			`"strings"`,
-		},
-		thirdParty: importList{
-			`"github.com/pkg/errors"`,
-			`"github.com/spf13/viper"`,
-			`"github.com/vattle/sqlboiler/bdb/drivers"`,
-			`"github.com/vattle/sqlboiler/randomize"`,
-			`_ "github.com/go-sql-driver/mysql"`,
-		},
-	},
+// Remove an import matching the match string under the specified key.
+// Remove will search both standard and thirdParty import lists for a match.
+func (m mapImports) Remove(key string, match string) {
+	mp := m[key]
+	for idx := 0; idx < len(mp.standard); idx++ {
+		if mp.standard[idx] == match {
+			mp.standard[idx] = mp.standard[len(mp.standard)-1]
+			mp.standard = mp.standard[:len(mp.standard)-1]
+			break
+		}
+	}
+	for idx := 0; idx < len(mp.thirdParty); idx++ {
+		if mp.thirdParty[idx] == match {
+			mp.thirdParty[idx] = mp.thirdParty[len(mp.thirdParty)-1]
+			mp.thirdParty = mp.thirdParty[:len(mp.thirdParty)-1]
+			break
+		}
+	}
+
+	// delete the key and return if both import lists are empty
+	if len(mp.thirdParty) == 0 && len(mp.standard) == 0 {
+		delete(m, key)
+		return
+	}
+
+	m[key] = mp
 }
 
-// importsBasedOnType imports are only included in the template output if the
-// database requires one of the following special types. Check
-// TranslateColumnType to see the type assignments.
-var importsBasedOnType = map[string]imports{
-	"null.Float32": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Float64": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Int": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Int8": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Int16": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Int32": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Int64": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Uint": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Uint8": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Uint16": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Uint32": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Uint64": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.String": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Bool": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Time": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.JSON": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"null.Bytes": {
-		thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
-	},
-	"time.Time": {
-		standard: importList{`"time"`},
-	},
-	"types.JSON": {
-		thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
-	},
-	"types.BytesArray": {
-		thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
-	},
-	"types.Int64Array": {
-		thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
-	},
-	"types.Float64Array": {
-		thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
-	},
-	"types.BoolArray": {
-		thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
-	},
-	"types.StringArray": {
-		thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
-	},
-	"types.Hstore": {
-		thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
-	},
+// Add an import under the specified key. If the key does not exist, it
+// will be created.
+func (m mapImports) Add(key string, value string, thirdParty bool) {
+	mp := m[key]
+	if thirdParty {
+		mp.thirdParty = append(mp.thirdParty, value)
+	} else {
+		mp.standard = append(mp.standard, value)
+	}
+
+	m[key] = mp
+}
+
+// Remove an import matching the match string under the specified key.
+// Remove will search both standard and thirdParty import lists for a match.
+func (i *imports) Remove(match string) {
+	for idx := 0; idx < len(i.standard); idx++ {
+		if i.standard[idx] == match {
+			i.standard[idx] = i.standard[len(i.standard)-1]
+			i.standard = i.standard[:len(i.standard)-1]
+			break
+		}
+	}
+	for idx := 0; idx < len(i.thirdParty); idx++ {
+		if i.thirdParty[idx] == match {
+			i.thirdParty[idx] = i.thirdParty[len(i.thirdParty)-1]
+			i.thirdParty = i.thirdParty[:len(i.thirdParty)-1]
+			break
+		}
+	}
+}
+
+// Add an import under the specified key. If the key does not exist, it
+// will be created.
+func (i *imports) Add(value string, thirdParty bool) {
+	if thirdParty {
+		i.thirdParty = append(i.thirdParty, value)
+	} else {
+		i.standard = append(i.standard, value)
+	}
 }
diff --git a/boilingcore/imports_test.go b/boilingcore/imports_test.go
index 43c46e5..411408b 100644
--- a/boilingcore/imports_test.go
+++ b/boilingcore/imports_test.go
@@ -54,6 +54,177 @@ func TestImportsSort(t *testing.T) {
 	}
 }
 
+func TestImportsAddAndRemove(t *testing.T) {
+	t.Parallel()
+
+	var imp imports
+	imp.Add("value", false)
+	if len(imp.standard) != 1 {
+		t.Errorf("expected len 1, got %d", len(imp.standard))
+	}
+	if imp.standard[0] != "value" {
+		t.Errorf("expected %q to be added", "value")
+	}
+	imp.Add("value2", true)
+	if len(imp.thirdParty) != 1 {
+		t.Errorf("expected len 1, got %d", len(imp.thirdParty))
+	}
+	if imp.thirdParty[0] != "value2" {
+		t.Errorf("expected %q to be added", "value2")
+	}
+
+	imp.Remove("value")
+	if len(imp.standard) != 0 {
+		t.Errorf("expected len 0, got %d", len(imp.standard))
+	}
+	imp.Remove("value")
+	if len(imp.standard) != 0 {
+		t.Errorf("expected len 0, got %d", len(imp.standard))
+	}
+	imp.Remove("value2")
+	if len(imp.thirdParty) != 0 {
+		t.Errorf("expected len 0, got %d", len(imp.thirdParty))
+	}
+
+	// Test deleting last element in len 2 slice
+	imp.Add("value3", false)
+	imp.Add("value4", false)
+	if len(imp.standard) != 2 {
+		t.Errorf("expected len 2, got %d", len(imp.standard))
+	}
+	imp.Remove("value4")
+	if len(imp.standard) != 1 {
+		t.Errorf("expected len 1, got %d", len(imp.standard))
+	}
+	if imp.standard[0] != "value3" {
+		t.Errorf("expected %q, got %q", "value3", imp.standard[0])
+	}
+	// Test deleting first element in len 2 slice
+	imp.Add("value4", false)
+	imp.Remove("value3")
+	if len(imp.standard) != 1 {
+		t.Errorf("expected len 1, got %d", len(imp.standard))
+	}
+	if imp.standard[0] != "value4" {
+		t.Errorf("expected %q, got %q", "value4", imp.standard[0])
+	}
+	imp.Remove("value2")
+	if len(imp.thirdParty) != 0 {
+		t.Errorf("expected len 0, got %d", len(imp.thirdParty))
+	}
+
+	// Test deleting last element in len 2 slice
+	imp.Add("value5", true)
+	imp.Add("value6", true)
+	if len(imp.thirdParty) != 2 {
+		t.Errorf("expected len 2, got %d", len(imp.thirdParty))
+	}
+	imp.Remove("value6")
+	if len(imp.thirdParty) != 1 {
+		t.Errorf("expected len 1, got %d", len(imp.thirdParty))
+	}
+	if imp.thirdParty[0] != "value5" {
+		t.Errorf("expected %q, got %q", "value5", imp.thirdParty[0])
+	}
+	// Test deleting first element in len 2 slice
+	imp.Add("value6", true)
+	imp.Remove("value5")
+	if len(imp.thirdParty) != 1 {
+		t.Errorf("expected len 1, got %d", len(imp.thirdParty))
+	}
+	if imp.thirdParty[0] != "value6" {
+		t.Errorf("expected %q, got %q", "value6", imp.thirdParty[0])
+	}
+}
+
+func TestMapImportsAddAndRemove(t *testing.T) {
+	t.Parallel()
+
+	imp := mapImports{}
+	imp.Add("cat", "value", false)
+	if len(imp["cat"].standard) != 1 {
+		t.Errorf("expected len 1, got %d", len(imp["cat"].standard))
+	}
+	if imp["cat"].standard[0] != "value" {
+		t.Errorf("expected %q to be added", "value")
+	}
+	imp.Add("cat", "value2", true)
+	if len(imp["cat"].thirdParty) != 1 {
+		t.Errorf("expected len 1, got %d", len(imp["cat"].thirdParty))
+	}
+	if imp["cat"].thirdParty[0] != "value2" {
+		t.Errorf("expected %q to be added", "value2")
+	}
+
+	imp.Remove("cat", "value")
+	if len(imp["cat"].standard) != 0 {
+		t.Errorf("expected len 0, got %d", len(imp["cat"].standard))
+	}
+	imp.Remove("cat", "value")
+	if len(imp["cat"].standard) != 0 {
+		t.Errorf("expected len 0, got %d", len(imp["cat"].standard))
+	}
+	imp.Remove("cat", "value2")
+	if len(imp["cat"].thirdParty) != 0 {
+		t.Errorf("expected len 0, got %d", len(imp["cat"].thirdParty))
+	}
+	// If there are no elements left in key, test key is deleted
+	_, ok := imp["cat"]
+	if ok {
+		t.Errorf("expected cat key to be deleted when list empty")
+	}
+
+	// Test deleting last element in len 2 slice
+	imp.Add("cat", "value3", false)
+	imp.Add("cat", "value4", false)
+	if len(imp["cat"].standard) != 2 {
+		t.Errorf("expected len 2, got %d", len(imp["cat"].standard))
+	}
+	imp.Remove("cat", "value4")
+	if len(imp["cat"].standard) != 1 {
+		t.Errorf("expected len 1, got %d", len(imp["cat"].standard))
+	}
+	if imp["cat"].standard[0] != "value3" {
+		t.Errorf("expected %q, got %q", "value3", imp["cat"].standard[0])
+	}
+	// Test deleting first element in len 2 slice
+	imp.Add("cat", "value4", false)
+	imp.Remove("cat", "value3")
+	if len(imp["cat"].standard) != 1 {
+		t.Errorf("expected len 1, got %d", len(imp["cat"].standard))
+	}
+	if imp["cat"].standard[0] != "value4" {
+		t.Errorf("expected %q, got %q", "value4", imp["cat"].standard[0])
+	}
+	imp.Remove("cat", "value2")
+	if len(imp["cat"].thirdParty) != 0 {
+		t.Errorf("expected len 0, got %d", len(imp["cat"].thirdParty))
+	}
+
+	// Test deleting last element in len 2 slice
+	imp.Add("dog", "value5", true)
+	imp.Add("dog", "value6", true)
+	if len(imp["dog"].thirdParty) != 2 {
+		t.Errorf("expected len 2, got %d", len(imp["dog"].thirdParty))
+	}
+	imp.Remove("dog", "value6")
+	if len(imp["dog"].thirdParty) != 1 {
+		t.Errorf("expected len 1, got %d", len(imp["dog"].thirdParty))
+	}
+	if imp["dog"].thirdParty[0] != "value5" {
+		t.Errorf("expected %q, got %q", "value5", imp["dog"].thirdParty[0])
+	}
+	// Test deleting first element in len 2 slice
+	imp.Add("dog", "value6", true)
+	imp.Remove("dog", "value5")
+	if len(imp["dog"].thirdParty) != 1 {
+		t.Errorf("expected len 1, got %d", len(imp["dog"].thirdParty))
+	}
+	if imp["dog"].thirdParty[0] != "value6" {
+		t.Errorf("expected %q, got %q", "value6", imp["dog"].thirdParty[0])
+	}
+}
+
 func TestCombineTypeImports(t *testing.T) {
 	t.Parallel()
 
@@ -94,7 +265,9 @@ func TestCombineTypeImports(t *testing.T) {
 		},
 	}
 
-	res1 := combineTypeImports(imports1, importsBasedOnType, cols)
+	imps := newImporter()
+
+	res1 := combineTypeImports(imports1, imps.basedOnType, cols)
 
 	if !reflect.DeepEqual(res1, importsExpected) {
 		t.Errorf("Expected res1 to match importsExpected, got:\n\n%#v\n", res1)
@@ -112,7 +285,7 @@ func TestCombineTypeImports(t *testing.T) {
 		},
 	}
 
-	res2 := combineTypeImports(imports2, importsBasedOnType, cols)
+	res2 := combineTypeImports(imports2, imps.basedOnType, cols)
 
 	if !reflect.DeepEqual(res2, importsExpected) {
 		t.Errorf("Expected res2 to match importsExpected, got:\n\n%#v\n", res1)
diff --git a/boilingcore/output.go b/boilingcore/output.go
index ffbde94..e7192f1 100644
--- a/boilingcore/output.go
+++ b/boilingcore/output.go
@@ -38,7 +38,7 @@ func generateOutput(state *State, data *templateData) error {
 		state:                state,
 		data:                 data,
 		templates:            state.Templates,
-		importSet:            defaultTemplateImports,
+		importSet:            state.Importer.standard,
 		combineImportsOnType: true,
 		fileSuffix:           ".go",
 	})
@@ -50,7 +50,7 @@ func generateTestOutput(state *State, data *templateData) error {
 		state:                state,
 		data:                 data,
 		templates:            state.TestTemplates,
-		importSet:            defaultTestTemplateImports,
+		importSet:            state.Importer.testStandard,
 		combineImportsOnType: false,
 		fileSuffix:           "_test.go",
 	})
@@ -63,7 +63,7 @@ func generateSingletonOutput(state *State, data *templateData) error {
 		state:          state,
 		data:           data,
 		templates:      state.SingletonTemplates,
-		importNamedSet: defaultSingletonTemplateImports,
+		importNamedSet: state.Importer.singleton,
 		fileSuffix:     ".go",
 	})
 }
@@ -75,7 +75,7 @@ func generateSingletonTestOutput(state *State, data *templateData) error {
 		state:          state,
 		data:           data,
 		templates:      state.SingletonTestTemplates,
-		importNamedSet: defaultSingletonTestTemplateImports,
+		importNamedSet: state.Importer.testSingleton,
 		fileSuffix:     ".go",
 	})
 }
@@ -106,7 +106,7 @@ func executeTemplates(e executeTemplateData) error {
 	imps.standard = e.importSet.standard
 	imps.thirdParty = e.importSet.thirdParty
 	if e.combineImportsOnType {
-		imps = combineTypeImports(imps, importsBasedOnType, e.data.Table.Columns)
+		imps = combineTypeImports(imps, e.state.Importer.basedOnType, e.data.Table.Columns)
 	}
 
 	writeFileDisclaimer(out)
@@ -170,8 +170,8 @@ func generateTestMainOutput(state *State, data *templateData) error {
 	out.Reset()
 
 	var imps imports
-	imps.standard = defaultTestMainImports[state.Config.DriverName].standard
-	imps.thirdParty = defaultTestMainImports[state.Config.DriverName].thirdParty
+	imps.standard = state.Importer.testMain[state.Config.DriverName].standard
+	imps.thirdParty = state.Importer.testMain[state.Config.DriverName].thirdParty
 
 	writeFileDisclaimer(out)
 	writePackageName(out, state.Config.PkgName)

From 37477542361ac2382cf860f06f8b289037b58044 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sun, 5 Feb 2017 21:41:30 +1000
Subject: [PATCH 043/179] export importer members and add basepath for Stat

---
 boilingcore/boilingcore.go  |  7 ++++++-
 boilingcore/imports.go      | 24 ++++++++++++------------
 boilingcore/imports_test.go |  4 ++--
 boilingcore/output.go       | 14 +++++++-------
 4 files changed, 27 insertions(+), 22 deletions(-)

diff --git a/boilingcore/boilingcore.go b/boilingcore/boilingcore.go
index e396994..cf33e0e 100644
--- a/boilingcore/boilingcore.go
+++ b/boilingcore/boilingcore.go
@@ -213,6 +213,11 @@ func (s *State) initTemplates() error {
 
 // processReplacements loads any replacement templates
 func (s *State) processReplacements() error {
+	basePath, err := getBasePath(s.Config.BaseDir)
+	if err != nil {
+		return err
+	}
+
 	for _, replace := range s.Config.Replacements {
 		splits := strings.Split(replace, ":")
 		if len(splits) != 2 {
@@ -222,7 +227,7 @@ func (s *State) processReplacements() error {
 		var toReplaceFname string
 		toReplace, replaceWith := splits[0], splits[1]
 
-		inf, err := os.Stat(toReplace)
+		inf, err := os.Stat(filepath.Join(basePath, toReplace))
 		if err != nil {
 			return errors.Errorf("cannot stat %q", toReplace)
 		}
diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index ec2752e..3ad8411 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -144,22 +144,22 @@ func removeDuplicates(dedup []string) []string {
 type mapImports map[string]imports
 
 type importer struct {
-	standard     imports
-	testStandard imports
+	Standard     imports
+	TestStandard imports
 
-	singleton     mapImports
-	testSingleton mapImports
+	Singleton     mapImports
+	TestSingleton mapImports
 
-	testMain mapImports
+	TestMain mapImports
 
-	basedOnType mapImports
+	BasedOnType mapImports
 }
 
 // newImporter returns an importer struct with default import values
 func newImporter() importer {
 	var imp importer
 
-	imp.standard = imports{
+	imp.Standard = imports{
 		standard: importList{
 			`"bytes"`,
 			`"database/sql"`,
@@ -178,7 +178,7 @@ func newImporter() importer {
 		},
 	}
 
-	imp.singleton = mapImports{
+	imp.Singleton = mapImports{
 		"boil_queries": {
 			thirdParty: importList{
 				`"github.com/vattle/sqlboiler/boil"`,
@@ -194,7 +194,7 @@ func newImporter() importer {
 		},
 	}
 
-	imp.testStandard = imports{
+	imp.TestStandard = imports{
 		standard: importList{
 			`"bytes"`,
 			`"reflect"`,
@@ -207,7 +207,7 @@ func newImporter() importer {
 		},
 	}
 
-	imp.testSingleton = mapImports{
+	imp.TestSingleton = mapImports{
 		"boil_main_test": {
 			standard: importList{
 				`"database/sql"`,
@@ -246,7 +246,7 @@ func newImporter() importer {
 		},
 	}
 
-	imp.testMain = mapImports{
+	imp.TestMain = mapImports{
 		"postgres": {
 			standard: importList{
 				`"bytes"`,
@@ -290,7 +290,7 @@ func newImporter() importer {
 	// basedOnType imports are only included in the template output if the
 	// database requires one of the following special types. Check
 	// TranslateColumnType to see the type assignments.
-	imp.basedOnType = mapImports{
+	imp.BasedOnType = mapImports{
 		"null.Float32": {
 			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
 		},
diff --git a/boilingcore/imports_test.go b/boilingcore/imports_test.go
index 411408b..6f2cde4 100644
--- a/boilingcore/imports_test.go
+++ b/boilingcore/imports_test.go
@@ -267,7 +267,7 @@ func TestCombineTypeImports(t *testing.T) {
 
 	imps := newImporter()
 
-	res1 := combineTypeImports(imports1, imps.basedOnType, cols)
+	res1 := combineTypeImports(imports1, imps.BasedOnType, cols)
 
 	if !reflect.DeepEqual(res1, importsExpected) {
 		t.Errorf("Expected res1 to match importsExpected, got:\n\n%#v\n", res1)
@@ -285,7 +285,7 @@ func TestCombineTypeImports(t *testing.T) {
 		},
 	}
 
-	res2 := combineTypeImports(imports2, imps.basedOnType, cols)
+	res2 := combineTypeImports(imports2, imps.BasedOnType, cols)
 
 	if !reflect.DeepEqual(res2, importsExpected) {
 		t.Errorf("Expected res2 to match importsExpected, got:\n\n%#v\n", res1)
diff --git a/boilingcore/output.go b/boilingcore/output.go
index e7192f1..64f28b5 100644
--- a/boilingcore/output.go
+++ b/boilingcore/output.go
@@ -38,7 +38,7 @@ func generateOutput(state *State, data *templateData) error {
 		state:                state,
 		data:                 data,
 		templates:            state.Templates,
-		importSet:            state.Importer.standard,
+		importSet:            state.Importer.Standard,
 		combineImportsOnType: true,
 		fileSuffix:           ".go",
 	})
@@ -50,7 +50,7 @@ func generateTestOutput(state *State, data *templateData) error {
 		state:                state,
 		data:                 data,
 		templates:            state.TestTemplates,
-		importSet:            state.Importer.testStandard,
+		importSet:            state.Importer.TestStandard,
 		combineImportsOnType: false,
 		fileSuffix:           "_test.go",
 	})
@@ -63,7 +63,7 @@ func generateSingletonOutput(state *State, data *templateData) error {
 		state:          state,
 		data:           data,
 		templates:      state.SingletonTemplates,
-		importNamedSet: state.Importer.singleton,
+		importNamedSet: state.Importer.Singleton,
 		fileSuffix:     ".go",
 	})
 }
@@ -75,7 +75,7 @@ func generateSingletonTestOutput(state *State, data *templateData) error {
 		state:          state,
 		data:           data,
 		templates:      state.SingletonTestTemplates,
-		importNamedSet: state.Importer.testSingleton,
+		importNamedSet: state.Importer.TestSingleton,
 		fileSuffix:     ".go",
 	})
 }
@@ -106,7 +106,7 @@ func executeTemplates(e executeTemplateData) error {
 	imps.standard = e.importSet.standard
 	imps.thirdParty = e.importSet.thirdParty
 	if e.combineImportsOnType {
-		imps = combineTypeImports(imps, e.state.Importer.basedOnType, e.data.Table.Columns)
+		imps = combineTypeImports(imps, e.state.Importer.BasedOnType, e.data.Table.Columns)
 	}
 
 	writeFileDisclaimer(out)
@@ -170,8 +170,8 @@ func generateTestMainOutput(state *State, data *templateData) error {
 	out.Reset()
 
 	var imps imports
-	imps.standard = state.Importer.testMain[state.Config.DriverName].standard
-	imps.thirdParty = state.Importer.testMain[state.Config.DriverName].thirdParty
+	imps.standard = state.Importer.TestMain[state.Config.DriverName].standard
+	imps.thirdParty = state.Importer.TestMain[state.Config.DriverName].thirdParty
 
 	writeFileDisclaimer(out)
 	writePackageName(out, state.Config.PkgName)

From 8aa4e2148c0711d872e270dccff9b4a08325e664 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Fri, 24 Feb 2017 22:27:05 -0800
Subject: [PATCH 044/179] Use _ to avoid reserved words in func args

- Fix #107
---
 boilingcore/templates.go    |  3 ++-
 strmangle/strmangle.go      | 37 +++++++++++++++++++++++++++++++++++++
 strmangle/strmangle_test.go | 20 ++++++++++++++++++++
 templates/14_find.tpl       |  2 +-
 templates/20_exists.tpl     |  2 +-
 5 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/boilingcore/templates.go b/boilingcore/templates.go
index 13f4142..dec57bb 100644
--- a/boilingcore/templates.go
+++ b/boilingcore/templates.go
@@ -168,7 +168,8 @@ func (o once) Put(s string) bool {
 // stringMap function.
 var templateStringMappers = map[string]func(string) string{
 	// String ops
-	"quoteWrap": func(a string) string { return fmt.Sprintf(`"%s"`, a) },
+	"quoteWrap":       func(a string) string { return fmt.Sprintf(`"%s"`, a) },
+	"replaceReserved": strmangle.ReplaceReservedWords,
 
 	// Casing
 	"titleCase": strmangle.TitleCase,
diff --git a/strmangle/strmangle.go b/strmangle/strmangle.go
index ab93d26..316e1b0 100644
--- a/strmangle/strmangle.go
+++ b/strmangle/strmangle.go
@@ -43,6 +43,34 @@ var uppercaseWords = map[string]struct{}{
 	"utf8":  {},
 }
 
+var reservedWords = map[string]struct{}{
+	"break":       {},
+	"case":        {},
+	"chan":        {},
+	"const":       {},
+	"continue":    {},
+	"default":     {},
+	"defer":       {},
+	"else":        {},
+	"fallthrough": {},
+	"for":         {},
+	"func":        {},
+	"go":          {},
+	"goto":        {},
+	"if":          {},
+	"import":      {},
+	"interface":   {},
+	"map":         {},
+	"package":     {},
+	"range":       {},
+	"return":      {},
+	"select":      {},
+	"struct":      {},
+	"switch":      {},
+	"type":        {},
+	"var":         {},
+}
+
 func init() {
 	// Our Boil inflection Ruleset does not include uncountable inflections.
 	// This way, people using words like Sheep will not have
@@ -630,3 +658,12 @@ func IsEnumNormal(values []string) bool {
 func ShouldTitleCaseEnum(value string) bool {
 	return rgxEnumShouldTitle.MatchString(value)
 }
+
+// ReplaceReservedWords takes a word and replaces it with word_ if it's found
+// in the list of reserved words.
+func ReplaceReservedWords(word string) string {
+	if _, ok := reservedWords[word]; ok {
+		return word + "_"
+	}
+	return word
+}
diff --git a/strmangle/strmangle_test.go b/strmangle/strmangle_test.go
index 2a14af5..b07cee6 100644
--- a/strmangle/strmangle_test.go
+++ b/strmangle/strmangle_test.go
@@ -580,3 +580,23 @@ func TestShouldTitleCaseEnum(t *testing.T) {
 		}
 	}
 }
+
+func TestReplaceReservedWords(t *testing.T) {
+	tests := []struct {
+		Word    string
+		Replace bool
+	}{
+		{"break", true},
+		{"id", false},
+		{"type", true},
+	}
+
+	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)
+		} else if !test.Replace && strings.HasSuffix(got, "_") {
+			t.Errorf("%i) want normal (%s), got: %s", i, test.Word, got)
+		}
+	}
+}
diff --git a/templates/14_find.tpl b/templates/14_find.tpl
index 4ce7b15..097f184 100644
--- a/templates/14_find.tpl
+++ b/templates/14_find.tpl
@@ -1,7 +1,7 @@
 {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
 {{- $varNameSingular := .Table.Name | singular | camelCase -}}
 {{- $colDefs := sqlColDefinitions .Table.Columns .Table.PKey.Columns -}}
-{{- $pkNames := $colDefs.Names | stringMap .StringFuncs.camelCase -}}
+{{- $pkNames := $colDefs.Names | stringMap .StringFuncs.camelCase | stringMap .StringFuncs.replaceReserved -}}
 {{- $pkArgs := joinSlices " " $pkNames $colDefs.Types | join ", "}}
 // Find{{$tableNameSingular}}G retrieves a single record by ID.
 func Find{{$tableNameSingular}}G({{$pkArgs}}, selectCols ...string) (*{{$tableNameSingular}}, error) {
diff --git a/templates/20_exists.tpl b/templates/20_exists.tpl
index 2e768f1..3a9c693 100644
--- a/templates/20_exists.tpl
+++ b/templates/20_exists.tpl
@@ -1,6 +1,6 @@
 {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
 {{- $colDefs := sqlColDefinitions .Table.Columns .Table.PKey.Columns -}}
-{{- $pkNames := $colDefs.Names | stringMap .StringFuncs.camelCase -}}
+{{- $pkNames := $colDefs.Names | stringMap .StringFuncs.camelCase | stringMap .StringFuncs.replaceReserved -}}
 {{- $pkArgs := joinSlices " " $pkNames $colDefs.Types | join ", " -}}
 {{- $schemaTable := .Table.Name | .SchemaTable}}
 // {{$tableNameSingular}}Exists checks if the {{$tableNameSingular}} row exists.

From a5cb765403b743ecaa6fc482384a2699c66538be Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Fri, 24 Feb 2017 22:52:09 -0800
Subject: [PATCH 045/179] Ensure created_at isn't updated when unnecessary

- When we build the update whitelist (when the user doesn't provide one)
  we simply say that the whitelist is all columns except pkeys. The
  reason we do this is because sqlboiler doesn't support dirty tracking
  and if you want to update just a few fields, it's easier to just
  explicitly pass a whitelist when you update. However, in the case of
  created_at - it's a field that's usually managed by us and so we
  should not be updating it unless a user explicitly requests it via the
  whitelist. So if the whitelist is empty we prune that column now if it
  exists from the auto-created whitelist.
- The user also reported that upsert has the same fate, but the logic is
  somewhat different there. It expects that there's a value for
  created_at or it assumes that one needs to be created. There's no
  more magic we can do around this one unfortunately. Upsert is a
  mythical beast that doesn't play as nicely with our model, so users
  will just have to be more careful.
- Fix #106
---
 templates/16_update.tpl | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index 0f5dad5..f84a35c 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -49,6 +49,11 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 
 	if !cached {
 		wl := strmangle.UpdateColumnSet({{$varNameSingular}}Columns, {{$varNameSingular}}PrimaryKeyColumns, whitelist)
+		{{- if not .NoAutoTimestamps}}
+		if len(whitelist) == 0 {
+			wl = strmangle.SetComplement(wl, []string{"created_at"})
+		}
+		{{end -}}
 		if len(wl) == 0 {
 			return errors.New("{{.PkgName}}: unable to update {{.Table.Name}}, could not build whitelist")
 		}

From 8f96ba35d61c6bcfc16b265fe4439dea521a94bc Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Wed, 1 Mar 2017 18:18:47 -0800
Subject: [PATCH 046/179] Allow insertion of only-defaulted tables

- Tables that are only comprised of default values and have nothing
  passed into them on insertion will no longer generate syntax errors.
---
 queries/query_builders.go | 21 ++++++++++++++++-----
 templates/15_insert.tpl   | 10 +++++++++-
 2 files changed, 25 insertions(+), 6 deletions(-)

diff --git a/queries/query_builders.go b/queries/query_builders.go
index 081ca58..683c6b5 100644
--- a/queries/query_builders.go
+++ b/queries/query_builders.go
@@ -190,12 +190,17 @@ func BuildUpsertQueryMySQL(dia Dialect, tableName string, update, whitelist []st
 	buf := strmangle.GetBuffer()
 	defer strmangle.PutBuffer(buf)
 
+	var columns string
+	if len(whitelist) != 0 {
+		columns = strings.Join(whitelist, ", ")
+	}
+
 	if len(update) == 0 {
 		fmt.Fprintf(
 			buf,
 			"INSERT IGNORE INTO %s (%s) VALUES (%s)",
 			tableName,
-			strings.Join(whitelist, ", "),
+			columns,
 			strmangle.Placeholders(dia.IndexPlaceholders, len(whitelist), 1, 1),
 		)
 		return buf.String()
@@ -205,7 +210,7 @@ func BuildUpsertQueryMySQL(dia Dialect, tableName string, update, whitelist []st
 		buf,
 		"INSERT INTO %s (%s) VALUES (%s) ON DUPLICATE KEY UPDATE ",
 		tableName,
-		strings.Join(whitelist, ", "),
+		columns,
 		strmangle.Placeholders(dia.IndexPlaceholders, len(whitelist), 1, 1),
 	)
 
@@ -232,12 +237,18 @@ func BuildUpsertQueryPostgres(dia Dialect, tableName string, updateOnConflict bo
 	buf := strmangle.GetBuffer()
 	defer strmangle.PutBuffer(buf)
 
+	columns := "DEFAULT VALUES"
+	if len(whitelist) != 0 {
+		columns = fmt.Sprintf("(%s) VALUES (%s)",
+			strings.Join(whitelist, ", "),
+			strmangle.Placeholders(dia.IndexPlaceholders, len(whitelist), 1, 1))
+	}
+
 	fmt.Fprintf(
 		buf,
-		"INSERT INTO %s (%s) VALUES (%s) ON CONFLICT ",
+		"INSERT INTO %s %s ON CONFLICT ",
 		tableName,
-		strings.Join(whitelist, ", "),
-		strmangle.Placeholders(dia.IndexPlaceholders, len(whitelist), 1, 1),
+		columns,
 	)
 
 	if !updateOnConflict || len(update) == 0 {
diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index adf5f72..5fea2c3 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -65,7 +65,15 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 		if err != nil {
 			return err
 		}
-		cache.query = fmt.Sprintf("INSERT INTO {{$schemaTable}} ({{.LQ}}%s{{.RQ}}) VALUES (%s)", strings.Join(wl, "{{.LQ}},{{.RQ}}"), strmangle.Placeholders(dialect.IndexPlaceholders, len(wl), 1, 1))
+		if len(wl) != 0 {
+			cache.query = fmt.Sprintf("INSERT INTO {{$schemaTable}} ({{.LQ}}%s{{.RQ}}) VALUES (%s)", strings.Join(wl, "{{.LQ}},{{.RQ}}"), strmangle.Placeholders(dialect.IndexPlaceholders, len(wl), 1, 1))
+		} else {
+			{{if eq .DriverName "mysql" -}}
+			cache.query = "INSERT INTO {{$schemaTable}} () VALUES ()"
+			{{else -}}
+			cache.query = "INSERT INTO {{$schemaTable}} DEFAULT VALUES"
+			{{end -}}
+		}
 
 		if len(cache.retMapping) != 0 {
 			{{if .UseLastInsertID -}}

From 9067237f32b9bab8ed50562c624fa517503a0abb Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Wed, 1 Mar 2017 18:31:16 -0800
Subject: [PATCH 047/179] Bump Version

---
 main.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/main.go b/main.go
index d601d0c..dd2620f 100644
--- a/main.go
+++ b/main.go
@@ -14,7 +14,7 @@ import (
 	"github.com/vattle/sqlboiler/boilingcore"
 )
 
-const sqlBoilerVersion = "2.1.10"
+const sqlBoilerVersion = "2.2.0"
 
 var (
 	cmdState  *boilingcore.State

From 60a40eaf48953e1a449a3ce003b963cc0752bcc7 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sat, 4 Mar 2017 12:17:26 +1000
Subject: [PATCH 048/179] Fix randomize vals wrapping around to ngative vals

* Use modulus to ensure values are within valid ranges
---
 randomize/randomize.go         | 29 +++++++++++++++--------------
 testdata/mysql_test_schema.sql | 13 +++++++++++++
 2 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/randomize/randomize.go b/randomize/randomize.go
index df5d75e..0dd2e42 100644
--- a/randomize/randomize.go
+++ b/randomize/randomize.go
@@ -4,6 +4,7 @@ package randomize
 import (
 	"database/sql"
 	"fmt"
+	"math"
 	"math/rand"
 	"reflect"
 	"regexp"
@@ -71,7 +72,7 @@ func NewSeed() *Seed {
 }
 
 func (s *Seed) nextInt() int {
-	return int(atomic.AddInt64((*int64)(s), 1))
+	return int(atomic.AddInt64((*int64)(s), 1)) % math.MaxInt32
 }
 
 // Struct gets its fields filled with random data based on the seed.
@@ -501,23 +502,23 @@ func getStructRandValue(s *Seed, typ reflect.Type) interface{} {
 	case typeNullFloat64:
 		return null.NewFloat64(float64(s.nextInt()%10)/10.0+float64(s.nextInt()%10), true)
 	case typeNullInt:
-		return null.NewInt(int(int32(s.nextInt())), true)
+		return null.NewInt(int(int32(s.nextInt()))%math.MaxInt32, true)
 	case typeNullInt8:
-		return null.NewInt8(int8(s.nextInt()), true)
+		return null.NewInt8(int8(s.nextInt())%math.MaxInt8, true)
 	case typeNullInt16:
-		return null.NewInt16(int16(s.nextInt()), true)
+		return null.NewInt16(int16(s.nextInt())%math.MaxInt16, true)
 	case typeNullInt32:
-		return null.NewInt32(int32(s.nextInt()), true)
+		return null.NewInt32(int32(s.nextInt())%math.MaxInt32, true)
 	case typeNullInt64:
 		return null.NewInt64(int64(s.nextInt()), true)
 	case typeNullUint:
 		return null.NewUint(uint(s.nextInt()), true)
 	case typeNullUint8:
-		return null.NewUint8(uint8(s.nextInt()), true)
+		return null.NewUint8(uint8(s.nextInt())%math.MaxUint8, true)
 	case typeNullUint16:
-		return null.NewUint16(uint16(s.nextInt()), true)
+		return null.NewUint16(uint16(s.nextInt())%math.MaxUint16, true)
 	case typeNullUint32:
-		return null.NewUint32(uint32(s.nextInt()), true)
+		return null.NewUint32(uint32(s.nextInt())%math.MaxUint32, true)
 	case typeNullUint64:
 		return null.NewUint64(uint64(s.nextInt()), true)
 	case typeNullBytes:
@@ -590,21 +591,21 @@ func getVariableRandValue(s *Seed, kind reflect.Kind, typ reflect.Type) interfac
 	case reflect.Int:
 		return s.nextInt()
 	case reflect.Int8:
-		return int8(s.nextInt())
+		return int8(s.nextInt() % math.MaxInt8)
 	case reflect.Int16:
-		return int16(s.nextInt())
+		return int16(s.nextInt() % math.MaxInt16)
 	case reflect.Int32:
-		return int32(s.nextInt())
+		return int32(s.nextInt() % math.MaxInt32)
 	case reflect.Int64:
 		return int64(s.nextInt())
 	case reflect.Uint:
 		return uint(s.nextInt())
 	case reflect.Uint8:
-		return uint8(s.nextInt())
+		return uint8(s.nextInt() % math.MaxUint8)
 	case reflect.Uint16:
-		return uint16(s.nextInt())
+		return uint16(s.nextInt() % math.MaxUint16)
 	case reflect.Uint32:
-		return uint32(s.nextInt())
+		return uint32(s.nextInt() % math.MaxUint32)
 	case reflect.Uint64:
 		return uint64(s.nextInt())
 	case reflect.Bool:
diff --git a/testdata/mysql_test_schema.sql b/testdata/mysql_test_schema.sql
index 4755a63..7ed866e 100644
--- a/testdata/mysql_test_schema.sql
+++ b/testdata/mysql_test_schema.sql
@@ -352,3 +352,16 @@ CREATE TABLE pilot_languages (
 ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pkey PRIMARY KEY (pilot_id, language_id);
 ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
 ALTER TABLE pilot_languages ADD CONSTRAINT languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id);
+
+CREATE TABLE powers_of_two (
+  vid int(10) unsigned NOT NULL AUTO_INCREMENT, 
+  name varchar(255) NOT NULL DEFAULT '',
+  machine_name varchar(255) NOT NULL DEFAULT '',
+  description longtext,
+  hierarchy tinyint(3) unsigned NOT NULL DEFAULT '0',
+  module varchar(255) NOT NULL DEFAULT '',
+  weight int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (vid),
+  UNIQUE KEY machine_name (machine_name),
+  KEY list (weight,name)
+) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

From e8723a2797b9608411b5b7649996836cf5514807 Mon Sep 17 00:00:00 2001
From: Patrick O'brien <nullbio@users.noreply.github.com>
Date: Sat, 4 Mar 2017 20:15:05 +1000
Subject: [PATCH 049/179] Fix modulus fix

---
 randomize/randomize.go | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/randomize/randomize.go b/randomize/randomize.go
index 0dd2e42..59f7eff 100644
--- a/randomize/randomize.go
+++ b/randomize/randomize.go
@@ -72,7 +72,7 @@ func NewSeed() *Seed {
 }
 
 func (s *Seed) nextInt() int {
-	return int(atomic.AddInt64((*int64)(s), 1)) % math.MaxInt32
+	return int(atomic.AddInt64((*int64)(s), 1) % math.MaxInt32)
 }
 
 // Struct gets its fields filled with random data based on the seed.
@@ -502,23 +502,23 @@ func getStructRandValue(s *Seed, typ reflect.Type) interface{} {
 	case typeNullFloat64:
 		return null.NewFloat64(float64(s.nextInt()%10)/10.0+float64(s.nextInt()%10), true)
 	case typeNullInt:
-		return null.NewInt(int(int32(s.nextInt()))%math.MaxInt32, true)
+		return null.NewInt(int(int32(s.nextInt()%math.MaxInt32)), true)
 	case typeNullInt8:
-		return null.NewInt8(int8(s.nextInt())%math.MaxInt8, true)
+		return null.NewInt8(int8(s.nextInt()%math.MaxInt8), true)
 	case typeNullInt16:
-		return null.NewInt16(int16(s.nextInt())%math.MaxInt16, true)
+		return null.NewInt16(int16(s.nextInt()%math.MaxInt16), true)
 	case typeNullInt32:
-		return null.NewInt32(int32(s.nextInt())%math.MaxInt32, true)
+		return null.NewInt32(int32(s.nextInt()%math.MaxInt32), true)
 	case typeNullInt64:
 		return null.NewInt64(int64(s.nextInt()), true)
 	case typeNullUint:
 		return null.NewUint(uint(s.nextInt()), true)
 	case typeNullUint8:
-		return null.NewUint8(uint8(s.nextInt())%math.MaxUint8, true)
+		return null.NewUint8(uint8(s.nextInt()%math.MaxUint8), true)
 	case typeNullUint16:
-		return null.NewUint16(uint16(s.nextInt())%math.MaxUint16, true)
+		return null.NewUint16(uint16(s.nextInt()%math.MaxUint16), true)
 	case typeNullUint32:
-		return null.NewUint32(uint32(s.nextInt())%math.MaxUint32, true)
+		return null.NewUint32(uint32(s.nextInt()%math.MaxUint32), true)
 	case typeNullUint64:
 		return null.NewUint64(uint64(s.nextInt()), true)
 	case typeNullBytes:

From e00ea6067963487bec2995e9bb2bf064a2c5ad05 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Mon, 13 Mar 2017 12:55:26 +0300
Subject: [PATCH 050/179] Initial MSSQL support

---
 bdb/drivers/mssql.go                          | 362 ++++++++++++++++++
 boilingcore/boilingcore.go                    |   9 +
 boilingcore/config.go                         |  11 +
 boilingcore/imports.go                        |  19 +
 main.go                                       |  36 ++
 templates/01_types.tpl                        |   2 +
 templates/02_hooks.tpl                        |  12 +
 templates/17_upsert.tpl                       |   2 +
 templates_test/hooks.tpl                      |   4 +
 templates_test/main_test/mssql_main.tpl       | 161 ++++++++
 templates_test/singleton/boil_main_test.tpl   |  16 +
 .../singleton/boil_queries_test.tpl           |   1 +
 templates_test/singleton/boil_suites_test.tpl |   3 +-
 templates_test/upsert.tpl                     |   2 +
 14 files changed, 639 insertions(+), 1 deletion(-)
 create mode 100644 bdb/drivers/mssql.go
 create mode 100644 templates_test/main_test/mssql_main.tpl

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
new file mode 100644
index 0000000..4d7c0af
--- /dev/null
+++ b/bdb/drivers/mssql.go
@@ -0,0 +1,362 @@
+package drivers
+
+import (
+	"database/sql"
+	"fmt"
+	"net/url"
+	"strings"
+
+	_ "github.com/denisenkom/go-mssqldb"
+	"github.com/pkg/errors"
+	"github.com/vattle/sqlboiler/bdb"
+)
+
+// MSSQLDriver holds the database connection string and a handle
+// to the database connection.
+type MSSQLDriver struct {
+	connStr string
+	dbConn  *sql.DB
+}
+
+// NewMSSQLDriver takes the database connection details as parameters and
+// returns a pointer to a MSSQLDriver object. Note that it is required to
+// call MSSQLDriver.Open() and MSSQLDriver.Close() to open and close
+// the database connection once an object has been obtained.
+func NewMSSQLDriver(user, pass, dbname, host string, port int, sslmode string) *MSSQLDriver {
+	driver := MSSQLDriver{
+		connStr: MSSQLBuildQueryString(user, pass, dbname, host, port, sslmode),
+	}
+
+	return &driver
+}
+
+// MSSQLBuildQueryString builds a query string for MSSQL.
+func MSSQLBuildQueryString(user, pass, dbname, host string, port int, sslmode string) string {
+
+	query := url.Values{}
+	query.Add("database", dbname)
+	query.Add("encrypt", sslmode)
+
+	u := &url.URL{
+		Scheme: "sqlserver",
+		User:   url.UserPassword(user, pass),
+		Host:   fmt.Sprintf("%s:%d", host, port),
+		// Path:  instance, // if connecting to an instance instead of a port
+		RawQuery: query.Encode(),
+	}
+
+	return u.String()
+}
+
+// Open opens the database connection using the connection string
+func (m *MSSQLDriver) Open() error {
+	var err error
+	m.dbConn, err = sql.Open("mssql", m.connStr)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// Close closes the database connection
+func (m *MSSQLDriver) Close() {
+	m.dbConn.Close()
+}
+
+// UseLastInsertID returns false for postgres
+func (m *MSSQLDriver) UseLastInsertID() bool {
+	return true
+}
+
+// TableNames connects to the postgres database and
+// retrieves all table names from the information_schema where the
+// table schema is public.
+func (m *MSSQLDriver) TableNames(schema string, whitelist, blacklist []string) ([]string, error) {
+	var names []string
+
+	query := fmt.Sprintf(`select table_name from information_schema.tables where table_schema = ? and table_type = 'BASE TABLE'`)
+	args := []interface{}{schema}
+	if len(whitelist) > 0 {
+		query += fmt.Sprintf(" and table_name in (%s);", strings.Repeat(",?", len(whitelist))[1:])
+		for _, w := range whitelist {
+			args = append(args, w)
+		}
+	} else if len(blacklist) > 0 {
+		query += fmt.Sprintf(" and table_name not in (%s);", strings.Repeat(",?", len(blacklist))[1:])
+		for _, b := range blacklist {
+			args = append(args, b)
+		}
+	}
+
+	rows, err := m.dbConn.Query(query, args...)
+
+	if err != nil {
+		return nil, err
+	}
+
+	defer rows.Close()
+	for rows.Next() {
+		var name string
+		if err := rows.Scan(&name); err != nil {
+			return nil, err
+		}
+		names = append(names, name)
+	}
+
+	return names, nil
+}
+
+// Columns takes a table name and attempts to retrieve the table information
+// from the database information_schema.columns. It retrieves the column names
+// and column types and returns those as a []Column after TranslateColumnType()
+// converts the SQL types to Go types, for example: "varchar" to "string"
+func (m *MSSQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
+	var columns []bdb.Column
+
+	rows, err := m.dbConn.Query(`
+	SELECT column_name,
+       CASE
+         WHEN CHARACTER_MAXIMUM_LENGTH IS NULL THEN data_type
+         ELSE data_type + '(' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) + ')'
+       END AS full_type,
+       data_type,
+	   column_default,
+       CASE
+         WHEN IS_NULLABLE = 'YES' THEN 1
+         ELSE 0
+       END AS is_nullable,
+       CASE
+         WHEN EXISTS (SELECT c.column_name
+                      FROM information_schema.table_constraints tc
+                        INNER JOIN information_schema.key_column_usage kcu
+                                ON tc.constraint_name = kcu.constraint_name
+                               AND tc.table_name = kcu.table_name
+                               AND tc.table_schema = kcu.table_schema
+                      WHERE c.column_name = kcu.column_name
+                      AND   tc.table_name = c.table_name
+                      AND   (tc.constraint_type = 'PRIMARY KEY' OR tc.constraint_type = 'UNIQUE')
+                      AND   (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) THEN 1
+         ELSE 0
+       END AS is_unique
+	FROM INFORMATION_SCHEMA.columns c
+	where table_name = ? and table_schema = ?;
+	`, tableName, schema)
+
+	if err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	for rows.Next() {
+		var colName, colType, colFullType string
+		var nullable, unique bool
+		var defaultValue *string
+		if err := rows.Scan(&colName, &colFullType, &colType, &defaultValue, &nullable, &unique); err != nil {
+			return nil, errors.Wrapf(err, "unable to scan for table %s", tableName)
+		}
+
+		column := bdb.Column{
+			Name:       colName,
+			FullDBType: colFullType, // example: tinyint(1) instead of tinyint
+			DBType:     colType,
+			Nullable:   nullable,
+			Unique:     unique,
+		}
+
+		if defaultValue != nil && *defaultValue != "NULL" {
+			column.Default = *defaultValue
+		}
+
+		columns = append(columns, column)
+	}
+
+	return columns, nil
+}
+
+// PrimaryKeyInfo looks up the primary key for a table.
+func (m *MSSQLDriver) PrimaryKeyInfo(schema, tableName string) (*bdb.PrimaryKey, error) {
+	pkey := &bdb.PrimaryKey{}
+	var err error
+
+	query := `
+	select tc.constraint_name
+	from information_schema.table_constraints as tc
+	where tc.table_name = ? and tc.constraint_type = 'PRIMARY KEY' and tc.table_schema = ?;`
+
+	row := m.dbConn.QueryRow(query, tableName, schema)
+	if err = row.Scan(&pkey.Name); err != nil {
+		if err == sql.ErrNoRows {
+			return nil, nil
+		}
+		return nil, err
+	}
+
+	queryColumns := `
+	select kcu.column_name
+	from   information_schema.key_column_usage as kcu
+	where  table_name = ? and constraint_name = ? and table_schema = ?;`
+
+	var rows *sql.Rows
+	if rows, err = m.dbConn.Query(queryColumns, tableName, pkey.Name, schema); err != nil {
+		return nil, err
+	}
+	defer rows.Close()
+
+	var columns []string
+	for rows.Next() {
+		var column string
+
+		err = rows.Scan(&column)
+		if err != nil {
+			return nil, err
+		}
+
+		columns = append(columns, column)
+	}
+
+	if err = rows.Err(); err != nil {
+		return nil, err
+	}
+
+	pkey.Columns = columns
+
+	return pkey, nil
+}
+
+// ForeignKeyInfo retrieves the foreign keys for a given table name.
+func (m *MSSQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) {
+	var fkeys []bdb.ForeignKey
+
+	query := `
+	SELECT 
+		ccu.constraint_name AS SourceConstraint
+		,ccu.table_name AS SourceTable
+		,ccu.column_name AS SourceColumn
+		,kcu.table_name AS TargetTable
+		,kcu.column_name AS TargetColumn
+	FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu
+    INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
+        ON ccu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME 
+    INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu 
+        ON kcu.CONSTRAINT_NAME = rc.UNIQUE_CONSTRAINT_NAME  
+	where ccu.table_schema = ? and ccu.constraint_schema = ? and ccu.table_name = ?
+	`
+
+	var rows *sql.Rows
+	var err error
+	if rows, err = m.dbConn.Query(query, schema, schema, tableName); err != nil {
+		return nil, err
+	}
+
+	for rows.Next() {
+		var fkey bdb.ForeignKey
+		var sourceTable string
+
+		fkey.Table = tableName
+		err = rows.Scan(&fkey.Name, &sourceTable, &fkey.Column, &fkey.ForeignTable, &fkey.ForeignColumn)
+		if err != nil {
+			return nil, err
+		}
+
+		fkeys = append(fkeys, fkey)
+	}
+
+	if err = rows.Err(); err != nil {
+		return nil, err
+	}
+
+	return fkeys, nil
+}
+
+// TranslateColumnType converts postgres database types to Go types, for example
+// "varchar" to "string" and "bigint" to "int64". It returns this parsed data
+// as a Column object.
+func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
+	if c.Nullable {
+		switch c.DBType {
+		case "tinyint":
+			// map tinyint(1) to bool if TinyintAsBool is true
+			if TinyintAsBool && c.FullDBType == "tinyint(1)" {
+				c.Type = "null.Bool"
+			} else {
+				c.Type = "null.Int8"
+			}
+		case "smallint":
+			c.Type = "null.Int16"
+		case "mediumint":
+			c.Type = "null.Int32"
+		case "int", "integer":
+			c.Type = "null.Int"
+		case "bigint":
+			c.Type = "null.Int64"
+		case "float":
+			c.Type = "null.Float32"
+		case "double", "double precision", "real":
+			c.Type = "null.Float64"
+		case "boolean", "bool":
+			c.Type = "null.Bool"
+		case "date", "datetime", "timestamp", "time":
+			c.Type = "null.Time"
+		case "binary", "varbinary", "tinyblob", "blob", "mediumblob", "longblob":
+			c.Type = "null.Bytes"
+		case "json":
+			c.Type = "types.JSON"
+		default:
+			c.Type = "null.String"
+		}
+	} else {
+		switch c.DBType {
+		case "tinyint":
+			// map tinyint(1) to bool if TinyintAsBool is true
+			if TinyintAsBool && c.FullDBType == "tinyint(1)" {
+				c.Type = "bool"
+			} else {
+				c.Type = "int8"
+			}
+		case "smallint":
+			c.Type = "int16"
+		case "mediumint":
+			c.Type = "int32"
+		case "int", "integer":
+			c.Type = "int"
+		case "bigint":
+			c.Type = "int64"
+		case "float":
+			c.Type = "float32"
+		case "double", "double precision", "real":
+			c.Type = "float64"
+		case "boolean", "bool":
+			c.Type = "bool"
+		case "date", "datetime", "timestamp", "time":
+			c.Type = "time.Time"
+		case "binary", "varbinary", "tinyblob", "blob", "mediumblob", "longblob":
+			c.Type = "[]byte"
+		case "json":
+			c.Type = "types.JSON"
+		default:
+			c.Type = "string"
+		}
+	}
+
+	return c
+}
+
+// RightQuote is the quoting character for the right side of the identifier
+func (m *MSSQLDriver) RightQuote() byte {
+	return '`'
+}
+
+// LeftQuote is the quoting character for the left side of the identifier
+func (m *MSSQLDriver) LeftQuote() byte {
+	return '`'
+}
+
+// IndexPlaceholders returns false to indicate MSSQL doesnt support indexed placeholders
+func (m *MSSQLDriver) IndexPlaceholders() bool {
+	return false
+}
diff --git a/boilingcore/boilingcore.go b/boilingcore/boilingcore.go
index cf33e0e..e6aeefb 100644
--- a/boilingcore/boilingcore.go
+++ b/boilingcore/boilingcore.go
@@ -305,6 +305,15 @@ func (s *State) initDriver(driverName string) error {
 			s.Config.MySQL.Port,
 			s.Config.MySQL.SSLMode,
 		)
+	case "mssql":
+		s.Driver = drivers.NewMSSQLDriver(
+			s.Config.MSSQL.User,
+			s.Config.MSSQL.Pass,
+			s.Config.MSSQL.DBName,
+			s.Config.MSSQL.Host,
+			s.Config.MSSQL.Port,
+			s.Config.MSSQL.SSLMode,
+		)
 	case "mock":
 		s.Driver = &drivers.MockDriver{}
 	}
diff --git a/boilingcore/config.go b/boilingcore/config.go
index 62da693..63b0552 100644
--- a/boilingcore/config.go
+++ b/boilingcore/config.go
@@ -19,6 +19,7 @@ type Config struct {
 
 	Postgres PostgresConfig
 	MySQL    MySQLConfig
+	MSSQL    MSSQLConfig
 }
 
 // PostgresConfig configures a postgres database
@@ -40,3 +41,13 @@ type MySQLConfig struct {
 	DBName  string
 	SSLMode string
 }
+
+// MSSQLConfig configures a mysql database
+type MSSQLConfig struct {
+	User    string
+	Pass    string
+	Host    string
+	Port    int
+	DBName  string
+	SSLMode string
+}
diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index 3ad8411..dba9143 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -285,6 +285,25 @@ func newImporter() importer {
 				`_ "github.com/go-sql-driver/mysql"`,
 			},
 		},
+		"mssql": {
+			standard: importList{
+				`"bytes"`,
+				`"database/sql"`,
+				`"fmt"`,
+				`"io"`,
+				`"io/ioutil"`,
+				`"os"`,
+				`"os/exec"`,
+				`"strings"`,
+			},
+			thirdParty: importList{
+				`"github.com/pkg/errors"`,
+				`"github.com/spf13/viper"`,
+				`"github.com/vattle/sqlboiler/bdb/drivers"`,
+				`"github.com/vattle/sqlboiler/randomize"`,
+				`_ "github.com/denisenkom/go-mssqldb"`,
+			},
+		},
 	}
 
 	// basedOnType imports are only included in the template output if the
diff --git a/main.go b/main.go
index dd2620f..3f6601e 100644
--- a/main.go
+++ b/main.go
@@ -255,6 +255,42 @@ func preRun(cmd *cobra.Command, args []string) error {
 		}
 	}
 
+	if driverName == "mssql" {
+		cmdConfig.MSSQL = boilingcore.MSSQLConfig{
+			User:    viper.GetString("mssql.user"),
+			Pass:    viper.GetString("mssql.pass"),
+			Host:    viper.GetString("mssql.host"),
+			Port:    viper.GetInt("mssql.port"),
+			DBName:  viper.GetString("mssql.dbname"),
+			SSLMode: viper.GetString("mssql.sslmode"),
+		}
+
+		// BUG: https://github.com/spf13/viper/issues/71
+		// Despite setting defaults, nested values don't get defaults
+		// Set them manually
+		if cmdConfig.MSSQL.SSLMode == "" {
+			cmdConfig.MSSQL.SSLMode = "true"
+			viper.Set("mssql.sslmode", cmdConfig.MSSQL.SSLMode)
+		}
+
+		if cmdConfig.MSSQL.Port == 0 {
+			cmdConfig.MSSQL.Port = 3306
+			viper.Set("mssql.port", cmdConfig.MSSQL.Port)
+		}
+
+		err = vala.BeginValidation().Validate(
+			vala.StringNotEmpty(cmdConfig.MSSQL.User, "mssql.user"),
+			vala.StringNotEmpty(cmdConfig.MSSQL.Host, "mssql.host"),
+			vala.Not(vala.Equals(cmdConfig.MSSQL.Port, 0, "mssql.port")),
+			vala.StringNotEmpty(cmdConfig.MSSQL.DBName, "mssql.dbname"),
+			vala.StringNotEmpty(cmdConfig.MSSQL.SSLMode, "mssql.sslmode"),
+		).Check()
+
+		if err != nil {
+			return commandFailure(err.Error())
+		}
+	}
+
 	cmdState, err = boilingcore.New(cmdConfig)
 	return err
 }
diff --git a/templates/01_types.tpl b/templates/01_types.tpl
index edf742f..ff497df 100644
--- a/templates/01_types.tpl
+++ b/templates/01_types.tpl
@@ -32,8 +32,10 @@ var (
 	{{$varNameSingular}}InsertCache = make(map[string]insertCache)
 	{{$varNameSingular}}UpdateCacheMut sync.RWMutex
 	{{$varNameSingular}}UpdateCache = make(map[string]updateCache)
+	{{if ne .DriverName "mssql"}}
 	{{$varNameSingular}}UpsertCacheMut sync.RWMutex
 	{{$varNameSingular}}UpsertCache = make(map[string]insertCache)
+	{{end}}
 )
 
 var (
diff --git a/templates/02_hooks.tpl b/templates/02_hooks.tpl
index 9815639..073c8e9 100644
--- a/templates/02_hooks.tpl
+++ b/templates/02_hooks.tpl
@@ -4,13 +4,17 @@
 var {{$varNameSingular}}BeforeInsertHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}BeforeUpdateHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}BeforeDeleteHooks []{{$tableNameSingular}}Hook
+{{- if ne .DriverName "mssql" -}}
 var {{$varNameSingular}}BeforeUpsertHooks []{{$tableNameSingular}}Hook
+{{- end}}
 
 var {{$varNameSingular}}AfterInsertHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}AfterSelectHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}AfterUpdateHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}AfterDeleteHooks []{{$tableNameSingular}}Hook
+{{- if ne .DriverName "mssql" -}}
 var {{$varNameSingular}}AfterUpsertHooks []{{$tableNameSingular}}Hook
+{{- end}}
 
 // doBeforeInsertHooks executes all "before insert" hooks.
 func (o *{{$tableNameSingular}}) doBeforeInsertHooks(exec boil.Executor) (err error) {
@@ -45,6 +49,7 @@ func (o *{{$tableNameSingular}}) doBeforeDeleteHooks(exec boil.Executor) (err er
 	return nil
 }
 
+{{- if ne .DriverName "mssql" -}}
 // doBeforeUpsertHooks executes all "before Upsert" hooks.
 func (o *{{$tableNameSingular}}) doBeforeUpsertHooks(exec boil.Executor) (err error) {
 	for _, hook := range {{$varNameSingular}}BeforeUpsertHooks {
@@ -55,6 +60,7 @@ func (o *{{$tableNameSingular}}) doBeforeUpsertHooks(exec boil.Executor) (err er
 
 	return nil
 }
+{{- end}}
 
 // doAfterInsertHooks executes all "after Insert" hooks.
 func (o *{{$tableNameSingular}}) doAfterInsertHooks(exec boil.Executor) (err error) {
@@ -100,6 +106,7 @@ func (o *{{$tableNameSingular}}) doAfterDeleteHooks(exec boil.Executor) (err err
 	return nil
 }
 
+{{- if ne .DriverName "mssql" -}}
 // doAfterUpsertHooks executes all "after Upsert" hooks.
 func (o *{{$tableNameSingular}}) doAfterUpsertHooks(exec boil.Executor) (err error) {
 	for _, hook := range {{$varNameSingular}}AfterUpsertHooks {
@@ -110,6 +117,7 @@ func (o *{{$tableNameSingular}}) doAfterUpsertHooks(exec boil.Executor) (err err
 
 	return nil
 }
+{{- end}}
 
 // Add{{$tableNameSingular}}Hook registers your hook function for all future operations.
 func Add{{$tableNameSingular}}Hook(hookPoint boil.HookPoint, {{$varNameSingular}}Hook {{$tableNameSingular}}Hook) {
@@ -120,8 +128,10 @@ func Add{{$tableNameSingular}}Hook(hookPoint boil.HookPoint, {{$varNameSingular}
 			{{$varNameSingular}}BeforeUpdateHooks = append({{$varNameSingular}}BeforeUpdateHooks, {{$varNameSingular}}Hook)
 		case boil.BeforeDeleteHook:
 			{{$varNameSingular}}BeforeDeleteHooks = append({{$varNameSingular}}BeforeDeleteHooks, {{$varNameSingular}}Hook)
+		{{if ne .DriverName "mssql" -}}
 		case boil.BeforeUpsertHook:
 			{{$varNameSingular}}BeforeUpsertHooks = append({{$varNameSingular}}BeforeUpsertHooks, {{$varNameSingular}}Hook)
+		{{- end}}
 		case boil.AfterInsertHook:
 			{{$varNameSingular}}AfterInsertHooks = append({{$varNameSingular}}AfterInsertHooks, {{$varNameSingular}}Hook)
 		case boil.AfterSelectHook:
@@ -130,8 +140,10 @@ func Add{{$tableNameSingular}}Hook(hookPoint boil.HookPoint, {{$varNameSingular}
 			{{$varNameSingular}}AfterUpdateHooks = append({{$varNameSingular}}AfterUpdateHooks, {{$varNameSingular}}Hook)
 		case boil.AfterDeleteHook:
 			{{$varNameSingular}}AfterDeleteHooks = append({{$varNameSingular}}AfterDeleteHooks, {{$varNameSingular}}Hook)
+		{{- if ne .DriverName "mssql" -}}
 		case boil.AfterUpsertHook:
 			{{$varNameSingular}}AfterUpsertHooks = append({{$varNameSingular}}AfterUpsertHooks, {{$varNameSingular}}Hook)
+		{{- end}}
 	}
 }
 {{- end}}
diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index cf3b635..5bc9d3e 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -1,3 +1,4 @@
+{{- if ne .DriverName "mssql" -}}
 {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
 {{- $varNameSingular := .Table.Name | singular | camelCase -}}
 {{- $schemaTable := .Table.Name | .SchemaTable}}
@@ -207,3 +208,4 @@ CacheNoHooks:
 	return nil
 	{{- end}}
 }
+{{- end}}
\ No newline at end of file
diff --git a/templates_test/hooks.tpl b/templates_test/hooks.tpl
index 2cdca44..9f11698 100644
--- a/templates_test/hooks.tpl
+++ b/templates_test/hooks.tpl
@@ -38,6 +38,7 @@ func {{$varNameSingular}}AfterDeleteHook(e boil.Executor, o *{{$tableNameSingula
 	return nil
 }
 
+{{if ne .DriverName "mssql" -}}
 func {{$varNameSingular}}BeforeUpsertHook(e boil.Executor, o *{{$tableNameSingular}}) error {
 	*o = {{$tableNameSingular}}{}
 	return nil
@@ -47,6 +48,7 @@ func {{$varNameSingular}}AfterUpsertHook(e boil.Executor, o *{{$tableNameSingula
 	*o = {{$tableNameSingular}}{}
 	return nil
 }
+{{- end}}
 
 func test{{$tableNamePlural}}Hooks(t *testing.T) {
 	t.Parallel()
@@ -124,6 +126,7 @@ func test{{$tableNamePlural}}Hooks(t *testing.T) {
 	}
 	{{$varNameSingular}}AfterDeleteHooks = []{{$tableNameSingular}}Hook{}
 
+	{{- if ne .DriverName "mssql" -}}
 	Add{{$tableNameSingular}}Hook(boil.BeforeUpsertHook, {{$varNameSingular}}BeforeUpsertHook)
 	if err = o.doBeforeUpsertHooks(nil); err != nil {
 		t.Errorf("Unable to execute doBeforeUpsertHooks: %s", err)
@@ -141,5 +144,6 @@ func test{{$tableNamePlural}}Hooks(t *testing.T) {
 		t.Errorf("Expected AfterUpsertHook function to empty object, but got: %#v", o)
 	}
 	{{$varNameSingular}}AfterUpsertHooks = []{{$tableNameSingular}}Hook{}
+	{{- end}}
 }
 {{- end}}
diff --git a/templates_test/main_test/mssql_main.tpl b/templates_test/main_test/mssql_main.tpl
new file mode 100644
index 0000000..fab1afc
--- /dev/null
+++ b/templates_test/main_test/mssql_main.tpl
@@ -0,0 +1,161 @@
+type mssqlTester struct {
+	dbConn *sql.DB
+	dbName	string
+	host	string
+	user	string
+	pass	string
+	sslmode	string
+	port	int
+	optionFile string
+	testDBName string
+}
+
+func init() {
+	dbMain = &mssqlTester{}
+}
+
+func (m *mssqlTester) setup() error {
+	var err error
+	m.dbName = viper.GetString("mssql.dbname")
+	m.host = viper.GetString("mssql.host")
+	m.user = viper.GetString("mssql.user")
+	m.pass = viper.GetString("mssql.pass")
+	m.port = viper.GetInt("mssql.port")
+	m.sslmode = viper.GetString("mssql.sslmode")
+	// Create a randomized db name.
+	m.testDBName = randomize.StableDBName(m.dbName)
+	if err = m.makeOptionFile(); err != nil {
+		return errors.Wrap(err, "couldn't make option file")
+	}
+
+	if err = m.dropTestDB(); err != nil {
+		return err
+	}
+	if err = m.createTestDB(); err != nil {
+		return err
+	}
+
+	dumpCmd := exec.Command("mssqldump", m.defaultsFile(), "--no-data", m.dbName)
+	createCmd := exec.Command("mssql", m.defaultsFile(), "--database", m.testDBName)
+
+	r, w := io.Pipe()
+	dumpCmd.Stdout = w
+	createCmd.Stdin = newFKeyDestroyer(rgxMSSQLkey, r)
+
+	if err = dumpCmd.Start(); err != nil {
+		return errors.Wrap(err, "failed to start mssqldump command")
+	}
+	if err = createCmd.Start(); err != nil {
+		return errors.Wrap(err, "failed to start mssql command")
+	}
+
+	if err = dumpCmd.Wait(); err != nil {
+		fmt.Println(err)
+		return errors.Wrap(err, "failed to wait for mssqldump command")
+	}
+
+	w.Close() // After dumpCmd is done, close the write end of the pipe
+
+	if err = createCmd.Wait(); err != nil {
+		fmt.Println(err)
+		return errors.Wrap(err, "failed to wait for mssql command")
+	}
+
+	return nil
+}
+
+func (m *mssqlTester) sslMode(mode string) string {
+	switch mode {
+	case "true":
+		return "true"
+	case "false":
+		return "false"
+	default:
+		return "disable"
+	}
+}
+
+func (m *mssqlTester) defaultsFile() string {
+	return fmt.Sprintf("--defaults-file=%s", m.optionFile)
+}
+
+func (m *mssqlTester) makeOptionFile() error {
+	tmp, err := ioutil.TempFile("", "optionfile")
+	if err != nil {
+		return errors.Wrap(err, "failed to create option file")
+	}
+
+	fmt.Fprintln(tmp, "[client]")
+	fmt.Fprintf(tmp, "host=%s\n", m.host)
+	fmt.Fprintf(tmp, "port=%d\n", m.port)
+	fmt.Fprintf(tmp, "user=%s\n", m.user)
+	fmt.Fprintf(tmp, "password=%s\n", m.pass)
+	fmt.Fprintf(tmp, "ssl-mode=%s\n", m.sslMode(m.sslmode))
+
+	fmt.Fprintln(tmp, "[mssqldump]")
+	fmt.Fprintf(tmp, "host=%s\n", m.host)
+	fmt.Fprintf(tmp, "port=%d\n", m.port)
+	fmt.Fprintf(tmp, "user=%s\n", m.user)
+	fmt.Fprintf(tmp, "password=%s\n", m.pass)
+	fmt.Fprintf(tmp, "ssl-mode=%s\n", m.sslMode(m.sslmode))
+
+	m.optionFile = tmp.Name()
+
+	return tmp.Close()
+}
+
+func (m *mssqlTester) createTestDB() error {
+	sql := fmt.Sprintf("create database %s;", m.testDBName)
+	return m.runCmd(sql, "mssql")
+}
+
+func (m *mssqlTester) dropTestDB() error {
+	sql := fmt.Sprintf("drop database if exists %s;", m.testDBName)
+	return m.runCmd(sql, "mssql")
+}
+
+func (m *mssqlTester) teardown() error {
+	if m.dbConn != nil {
+		m.dbConn.Close()
+	}
+
+	if err := m.dropTestDB(); err != nil {
+		return err
+	}
+
+	return os.Remove(m.optionFile)
+}
+
+func (m *mssqlTester) runCmd(stdin, command string, args ...string) error {
+	args = append([]string{m.defaultsFile()}, args...)
+
+	cmd := exec.Command(command, args...)
+	cmd.Stdin = strings.NewReader(stdin)
+
+	stdout := &bytes.Buffer{}
+	stderr := &bytes.Buffer{}
+	cmd.Stdout = stdout
+	cmd.Stderr = stderr
+	if err := cmd.Run(); err != nil {
+	fmt.Println("failed running:", command, args)
+	fmt.Println(stdout.String())
+	fmt.Println(stderr.String())
+	return err
+	}
+
+	return nil
+}
+
+func (m *mssqlTester) conn() (*sql.DB, error) {
+	if m.dbConn != nil {
+	return m.dbConn, nil
+	}
+
+	var err error
+	m.dbConn, err = sql.Open("mssql", drivers.MSSQLBuildQueryString(m.user, m.pass, m.testDBName, m.host, m.port, m.sslmode))
+	if err != nil {
+	return nil, err
+	}
+
+	return m.dbConn, nil
+}
\ No newline at end of file
diff --git a/templates_test/singleton/boil_main_test.tpl b/templates_test/singleton/boil_main_test.tpl
index 0014a1e..ebb4758 100644
--- a/templates_test/singleton/boil_main_test.tpl
+++ b/templates_test/singleton/boil_main_test.tpl
@@ -104,6 +104,12 @@ func setConfigDefaults() {
 	if viper.GetInt("mysql.port") == 0 {
 		viper.Set("mysql.port", 3306)
 	}
+	if viper.GetString("mssql.sslmode") == "" {
+		viper.Set("mssql.sslmode", "true")
+	}
+	if viper.GetInt("mssql.port") == 0 {
+		viper.Set("mssql.port", 1433)
+	}
 }
 
 func validateConfig(driverName string) error {
@@ -127,5 +133,15 @@ func validateConfig(driverName string) error {
 		).Check()
 	}
 
+	if driverName == "mssql" {
+		return vala.BeginValidation().Validate(
+			vala.StringNotEmpty(viper.GetString("mssql.user"), "mssql.user"),
+			vala.StringNotEmpty(viper.GetString("mssql.host"), "mssql.host"),
+			vala.Not(vala.Equals(viper.GetInt("mssql.port"), 0, "mssql.port")),
+			vala.StringNotEmpty(viper.GetString("mssql.dbname"), "mssql.dbname"),
+			vala.StringNotEmpty(viper.GetString("mssql.sslmode"), "mssql.sslmode"),
+		).Check()
+	}
+
 	return errors.New("not a valid driver name")
 }
diff --git a/templates_test/singleton/boil_queries_test.tpl b/templates_test/singleton/boil_queries_test.tpl
index bd41389..f9c56b7 100644
--- a/templates_test/singleton/boil_queries_test.tpl
+++ b/templates_test/singleton/boil_queries_test.tpl
@@ -9,6 +9,7 @@ func MustTx(transactor boil.Transactor, err error) boil.Transactor {
 
 var rgxPGFkey = regexp.MustCompile(`(?m)^ALTER TABLE ONLY .*\n\s+ADD CONSTRAINT .*? FOREIGN KEY .*?;\n`)
 var rgxMySQLkey = regexp.MustCompile(`(?m)((,\n)?\s+CONSTRAINT.*?FOREIGN KEY.*?\n)+`)
+var rgxMSSQLkey = regexp.MustCompile(`(?m)^ALTER TABLE .*\n\s+ADD CONSTRAINT .*? FOREIGN KEY .*?;\n`)
 
 func newFKeyDestroyer(regex *regexp.Regexp, reader io.Reader) io.Reader {
 	return &fKeyDestroyer{
diff --git a/templates_test/singleton/boil_suites_test.tpl b/templates_test/singleton/boil_suites_test.tpl
index 08a5e21..c1c3516 100644
--- a/templates_test/singleton/boil_suites_test.tpl
+++ b/templates_test/singleton/boil_suites_test.tpl
@@ -327,7 +327,7 @@ func TestSliceUpdateAll(t *testing.T) {
   {{end -}}
   {{- end -}}
 }
-
+{{- if ne .DriverName "mssql" -}}
 func TestUpsert(t *testing.T) {
   {{- range $index, $table := .Tables}}
   {{- if $table.IsJoinTable -}}
@@ -337,3 +337,4 @@ func TestUpsert(t *testing.T) {
   {{end -}}
   {{- end -}}
 }
+{{- end -}}
\ No newline at end of file
diff --git a/templates_test/upsert.tpl b/templates_test/upsert.tpl
index f9c351e..68fc435 100644
--- a/templates_test/upsert.tpl
+++ b/templates_test/upsert.tpl
@@ -1,3 +1,4 @@
+{{- if ne .DriverName "mssql" -}}
 {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
 {{- $tableNamePlural := .Table.Name | plural | titleCase -}}
 {{- $varNamePlural := .Table.Name | plural | camelCase -}}
@@ -48,3 +49,4 @@ func test{{$tableNamePlural}}Upsert(t *testing.T) {
 		t.Error("want one record, got:", count)
 	}
 }
+{{- end}}
\ No newline at end of file

From 132339026ada1d2349441d283e51d44d937355b4 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Mon, 13 Mar 2017 16:24:08 +0300
Subject: [PATCH 051/179] Regular expression for FK destroyer

---
 templates_test/singleton/boil_queries_test.tpl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/templates_test/singleton/boil_queries_test.tpl b/templates_test/singleton/boil_queries_test.tpl
index f9c56b7..45ff788 100644
--- a/templates_test/singleton/boil_queries_test.tpl
+++ b/templates_test/singleton/boil_queries_test.tpl
@@ -9,7 +9,7 @@ func MustTx(transactor boil.Transactor, err error) boil.Transactor {
 
 var rgxPGFkey = regexp.MustCompile(`(?m)^ALTER TABLE ONLY .*\n\s+ADD CONSTRAINT .*? FOREIGN KEY .*?;\n`)
 var rgxMySQLkey = regexp.MustCompile(`(?m)((,\n)?\s+CONSTRAINT.*?FOREIGN KEY.*?\n)+`)
-var rgxMSSQLkey = regexp.MustCompile(`(?m)^ALTER TABLE .*\n\s+ADD CONSTRAINT .*? FOREIGN KEY .*?;\n`)
+var rgxMSSQLkey = regexp.MustCompile(`(?m)^ALTER TABLE .*ADD\s+CONSTRAINT .* FOREIGN KEY.*?.*\n?REFERENCES.*`)
 
 func newFKeyDestroyer(regex *regexp.Regexp, reader io.Reader) io.Reader {
 	return &fKeyDestroyer{

From 54af37ef9a77eb78912b5137734638383e9947f7 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Mon, 13 Mar 2017 16:25:12 +0300
Subject: [PATCH 052/179] SchemaTable with MSSQL support

---
 strmangle/strmangle.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/strmangle/strmangle.go b/strmangle/strmangle.go
index 316e1b0..4dc0b1b 100644
--- a/strmangle/strmangle.go
+++ b/strmangle/strmangle.go
@@ -85,7 +85,7 @@ func init() {
 // for Postgres: "schema_name"."table_name", versus
 // simply "table_name" for MySQL (because it does not support real schemas)
 func SchemaTable(lq, rq string, driver string, schema string, table string) string {
-	if driver == "postgres" && schema != "public" {
+	if (driver == "postgres" && schema != "public") || driver == "mssql" {
 		return fmt.Sprintf(`%s%s%s.%s%s%s`, lq, schema, rq, lq, table, rq)
 	}
 

From 2d3983b992db39d691f149d45eb684da839e313f Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Mon, 13 Mar 2017 16:27:16 +0300
Subject: [PATCH 053/179] Bit and tinyint data types support

---
 bdb/drivers/mssql.go | 18 ++++++------------
 1 file changed, 6 insertions(+), 12 deletions(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 4d7c0af..e918a58 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -279,13 +279,10 @@ func (m *MSSQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey
 func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 	if c.Nullable {
 		switch c.DBType {
+		case "bit":
+			c.Type = "bool"
 		case "tinyint":
-			// map tinyint(1) to bool if TinyintAsBool is true
-			if TinyintAsBool && c.FullDBType == "tinyint(1)" {
-				c.Type = "null.Bool"
-			} else {
-				c.Type = "null.Int8"
-			}
+			c.Type = "int8"
 		case "smallint":
 			c.Type = "null.Int16"
 		case "mediumint":
@@ -311,13 +308,10 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 		}
 	} else {
 		switch c.DBType {
+		case "bit":
+			c.Type = "bool"
 		case "tinyint":
-			// map tinyint(1) to bool if TinyintAsBool is true
-			if TinyintAsBool && c.FullDBType == "tinyint(1)" {
-				c.Type = "bool"
-			} else {
-				c.Type = "int8"
-			}
+			c.Type = "int8"
 		case "smallint":
 			c.Type = "int16"
 		case "mediumint":

From b4c9af72e7ace67efbc40a16660a10edf8f0b658 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Mon, 13 Mar 2017 16:28:23 +0300
Subject: [PATCH 054/179] Correct quote symbols

---
 bdb/drivers/mssql.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index e918a58..4c17c5d 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -342,12 +342,12 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 
 // RightQuote is the quoting character for the right side of the identifier
 func (m *MSSQLDriver) RightQuote() byte {
-	return '`'
+	return '\''
 }
 
 // LeftQuote is the quoting character for the left side of the identifier
 func (m *MSSQLDriver) LeftQuote() byte {
-	return '`'
+	return '\''
 }
 
 // IndexPlaceholders returns false to indicate MSSQL doesnt support indexed placeholders

From e2f32e746eac40e18f1dffda75534d4f2b34fece Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Mon, 13 Mar 2017 19:11:34 +0300
Subject: [PATCH 055/179] Main MSSQL test template

---
 boilingcore/imports.go                  |   2 -
 templates_test/main_test/mssql_main.tpl | 101 ++++++++----------------
 2 files changed, 31 insertions(+), 72 deletions(-)

diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index dba9143..eafcf28 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -290,8 +290,6 @@ func newImporter() importer {
 				`"bytes"`,
 				`"database/sql"`,
 				`"fmt"`,
-				`"io"`,
-				`"io/ioutil"`,
 				`"os"`,
 				`"os/exec"`,
 				`"strings"`,
diff --git a/templates_test/main_test/mssql_main.tpl b/templates_test/main_test/mssql_main.tpl
index fab1afc..82acbfc 100644
--- a/templates_test/main_test/mssql_main.tpl
+++ b/templates_test/main_test/mssql_main.tpl
@@ -1,12 +1,11 @@
 type mssqlTester struct {
-	dbConn *sql.DB
-	dbName	string
-	host	string
-	user	string
-	pass	string
-	sslmode	string
-	port	int
-	optionFile string
+	dbConn     *sql.DB
+	dbName     string
+	host       string
+	user       string
+	pass       string
+	sslmode    string
+	port       int
 	testDBName string
 }
 
@@ -24,9 +23,6 @@ func (m *mssqlTester) setup() error {
 	m.sslmode = viper.GetString("mssql.sslmode")
 	// Create a randomized db name.
 	m.testDBName = randomize.StableDBName(m.dbName)
-	if err = m.makeOptionFile(); err != nil {
-		return errors.Wrap(err, "couldn't make option file")
-	}
 
 	if err = m.dropTestDB(); err != nil {
 		return err
@@ -35,30 +31,20 @@ func (m *mssqlTester) setup() error {
 		return err
 	}
 
-	dumpCmd := exec.Command("mssqldump", m.defaultsFile(), "--no-data", m.dbName)
-	createCmd := exec.Command("mssql", m.defaultsFile(), "--database", m.testDBName)
+	createCmd := exec.Command("sqlcmd", "-S", m.host, "-U", m.user, "-P", m.pass, "-d", m.testDBName)
 
-	r, w := io.Pipe()
-	dumpCmd.Stdout = w
-	createCmd.Stdin = newFKeyDestroyer(rgxMSSQLkey, r)
+	f, err := os.Open("tables.sql")
+	defer f.Close()
+
+	createCmd.Stdin = newFKeyDestroyer(rgxMSSQLkey, f)
 
-	if err = dumpCmd.Start(); err != nil {
-		return errors.Wrap(err, "failed to start mssqldump command")
-	}
 	if err = createCmd.Start(); err != nil {
-		return errors.Wrap(err, "failed to start mssql command")
+		return errors.Wrap(err, "failed to start sqlcmd command")
 	}
 
-	if err = dumpCmd.Wait(); err != nil {
-		fmt.Println(err)
-		return errors.Wrap(err, "failed to wait for mssqldump command")
-	}
-
-	w.Close() // After dumpCmd is done, close the write end of the pipe
-
 	if err = createCmd.Wait(); err != nil {
 		fmt.Println(err)
-		return errors.Wrap(err, "failed to wait for mssql command")
+		return errors.Wrap(err, "failed to wait for sqlcmd command")
 	}
 
 	return nil
@@ -75,43 +61,20 @@ func (m *mssqlTester) sslMode(mode string) string {
 	}
 }
 
-func (m *mssqlTester) defaultsFile() string {
-	return fmt.Sprintf("--defaults-file=%s", m.optionFile)
-}
-
-func (m *mssqlTester) makeOptionFile() error {
-	tmp, err := ioutil.TempFile("", "optionfile")
-	if err != nil {
-		return errors.Wrap(err, "failed to create option file")
-	}
-
-	fmt.Fprintln(tmp, "[client]")
-	fmt.Fprintf(tmp, "host=%s\n", m.host)
-	fmt.Fprintf(tmp, "port=%d\n", m.port)
-	fmt.Fprintf(tmp, "user=%s\n", m.user)
-	fmt.Fprintf(tmp, "password=%s\n", m.pass)
-	fmt.Fprintf(tmp, "ssl-mode=%s\n", m.sslMode(m.sslmode))
-
-	fmt.Fprintln(tmp, "[mssqldump]")
-	fmt.Fprintf(tmp, "host=%s\n", m.host)
-	fmt.Fprintf(tmp, "port=%d\n", m.port)
-	fmt.Fprintf(tmp, "user=%s\n", m.user)
-	fmt.Fprintf(tmp, "password=%s\n", m.pass)
-	fmt.Fprintf(tmp, "ssl-mode=%s\n", m.sslMode(m.sslmode))
-
-	m.optionFile = tmp.Name()
-
-	return tmp.Close()
-}
-
 func (m *mssqlTester) createTestDB() error {
 	sql := fmt.Sprintf("create database %s;", m.testDBName)
-	return m.runCmd(sql, "mssql")
+	return m.runCmd(sql, "sqlcmd", "-S", m.host, "-U", m.user, "-P", m.pass)
 }
 
 func (m *mssqlTester) dropTestDB() error {
-	sql := fmt.Sprintf("drop database if exists %s;", m.testDBName)
-	return m.runCmd(sql, "mssql")
+	// Since MS SQL 2016 it can be done with
+	// DROP DATABASE [ IF EXISTS ] { database_name | database_snapshot_name } [ ,...n ] [;]
+	sql := fmt.Sprintf(`
+	IF EXISTS(SELECT name FROM sys.databases 
+		WHERE name = '%s')
+		DROP DATABASE %s
+	GO`, m.testDBName, m.testDBName)
+	return m.runCmd(sql, "sqlcmd", "-S", m.host, "-U", m.user, "-P", m.pass)
 }
 
 func (m *mssqlTester) teardown() error {
@@ -123,12 +86,10 @@ func (m *mssqlTester) teardown() error {
 		return err
 	}
 
-	return os.Remove(m.optionFile)
+	return nil
 }
 
 func (m *mssqlTester) runCmd(stdin, command string, args ...string) error {
-	args = append([]string{m.defaultsFile()}, args...)
-
 	cmd := exec.Command(command, args...)
 	cmd.Stdin = strings.NewReader(stdin)
 
@@ -137,10 +98,10 @@ func (m *mssqlTester) runCmd(stdin, command string, args ...string) error {
 	cmd.Stdout = stdout
 	cmd.Stderr = stderr
 	if err := cmd.Run(); err != nil {
-	fmt.Println("failed running:", command, args)
-	fmt.Println(stdout.String())
-	fmt.Println(stderr.String())
-	return err
+		fmt.Println("failed running:", command, args)
+		fmt.Println(stdout.String())
+		fmt.Println(stderr.String())
+		return err
 	}
 
 	return nil
@@ -148,14 +109,14 @@ func (m *mssqlTester) runCmd(stdin, command string, args ...string) error {
 
 func (m *mssqlTester) conn() (*sql.DB, error) {
 	if m.dbConn != nil {
-	return m.dbConn, nil
+		return m.dbConn, nil
 	}
 
 	var err error
 	m.dbConn, err = sql.Open("mssql", drivers.MSSQLBuildQueryString(m.user, m.pass, m.testDBName, m.host, m.port, m.sslmode))
 	if err != nil {
-	return nil, err
+		return nil, err
 	}
 
 	return m.dbConn, nil
-}
\ No newline at end of file
+}

From cbdbe4891a53b0ba9bdb955e51eba6890dadd8d8 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 11:13:56 +0300
Subject: [PATCH 056/179] MSSQL rows limit/offset via TOP or OFFSET ... FETCH
 NEXT ... ROWS

---
 bdb/drivers/mock.go        |  3 +++
 bdb/drivers/mssql.go       |  7 ++++++-
 bdb/drivers/mysql.go       |  5 +++++
 bdb/drivers/postgres.go    |  5 +++++
 bdb/interface.go           |  4 ++++
 bdb/interface_test.go      |  1 +
 boilingcore/boilingcore.go |  1 +
 queries/query.go           |  3 +++
 queries/query_builders.go  | 31 ++++++++++++++++++++++++++-----
 9 files changed, 54 insertions(+), 6 deletions(-)

diff --git a/bdb/drivers/mock.go b/bdb/drivers/mock.go
index abe85a4..1c91d0e 100644
--- a/bdb/drivers/mock.go
+++ b/bdb/drivers/mock.go
@@ -118,6 +118,9 @@ func (m *MockDriver) PrimaryKeyInfo(schema, tableName string) (*bdb.PrimaryKey,
 // UseLastInsertID returns a database mock LastInsertID compatibility flag
 func (m *MockDriver) UseLastInsertID() bool { return false }
 
+// UseTopClause returns a database mock SQL TOP clause compatibility flag
+func (m *MockDriver) UseTopClause() bool { return false }
+
 // Open mimics a database open call and returns nil for no error
 func (m *MockDriver) Open() error { return nil }
 
diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 4c17c5d..4e99e8c 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -64,8 +64,13 @@ func (m *MSSQLDriver) Close() {
 	m.dbConn.Close()
 }
 
-// UseLastInsertID returns false for postgres
+// UseLastInsertID returns false for mssql
 func (m *MSSQLDriver) UseLastInsertID() bool {
+	return false
+}
+
+// UseTopClause returns true to indicate MS SQL supports SQL TOP clause
+func (m *MSSQLDriver) UseTopClause() bool {
 	return true
 }
 
diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go
index 1d80634..ea24f1b 100644
--- a/bdb/drivers/mysql.go
+++ b/bdb/drivers/mysql.go
@@ -81,6 +81,11 @@ func (m *MySQLDriver) UseLastInsertID() bool {
 	return true
 }
 
+// UseTopClause returns false to indicate MySQL doesnt support SQL TOP clause
+func (m *MySQLDriver) UseTopClause() bool {
+	return false
+}
+
 // TableNames connects to the postgres database and
 // retrieves all table names from the information_schema where the
 // table schema is public.
diff --git a/bdb/drivers/postgres.go b/bdb/drivers/postgres.go
index 5ae0283..ec1aede 100644
--- a/bdb/drivers/postgres.go
+++ b/bdb/drivers/postgres.go
@@ -78,6 +78,11 @@ func (p *PostgresDriver) UseLastInsertID() bool {
 	return false
 }
 
+// UseTopClause returns false to indicate PSQL doesnt support SQL TOP clause
+func (m *PostgresDriver) UseTopClause() bool {
+	return false
+}
+
 // TableNames connects to the postgres database and
 // retrieves all table names from the information_schema where the
 // table schema is schema. It uses a whitelist and blacklist.
diff --git a/bdb/interface.go b/bdb/interface.go
index 2d90a1d..dfb33bc 100644
--- a/bdb/interface.go
+++ b/bdb/interface.go
@@ -18,6 +18,10 @@ type Interface interface {
 	// the sql.Exec result's LastInsertId
 	UseLastInsertID() bool
 
+	// UseTopClause should return true if the Database is capable of using
+	// the SQL TOP clause
+	UseTopClause() bool
+
 	// Open the database connection
 	Open() error
 	// Close the database connection
diff --git a/bdb/interface_test.go b/bdb/interface_test.go
index effeecf..4d429c6 100644
--- a/bdb/interface_test.go
+++ b/bdb/interface_test.go
@@ -10,6 +10,7 @@ type testMockDriver struct{}
 
 func (m testMockDriver) TranslateColumnType(c Column) Column { return c }
 func (m testMockDriver) UseLastInsertID() bool               { return false }
+func (m testMockDriver) UseTopClause() bool                  { return false }
 func (m testMockDriver) Open() error                         { return nil }
 func (m testMockDriver) Close()                              {}
 
diff --git a/boilingcore/boilingcore.go b/boilingcore/boilingcore.go
index e6aeefb..5e00687 100644
--- a/boilingcore/boilingcore.go
+++ b/boilingcore/boilingcore.go
@@ -325,6 +325,7 @@ func (s *State) initDriver(driverName string) error {
 	s.Dialect.LQ = s.Driver.LeftQuote()
 	s.Dialect.RQ = s.Driver.RightQuote()
 	s.Dialect.IndexPlaceholders = s.Driver.IndexPlaceholders()
+	s.Dialect.UseTopClause = s.Driver.UseTopClause()
 
 	return nil
 }
diff --git a/queries/query.go b/queries/query.go
index 5c2f3c9..8c2abdb 100644
--- a/queries/query.go
+++ b/queries/query.go
@@ -52,6 +52,9 @@ type Dialect struct {
 	// Bool flag indicating whether indexed
 	// placeholders ($1) are used, or ? placeholders.
 	IndexPlaceholders bool
+	// Bool flag indicating whether "TOP" or "LIMIT" clause
+	// must be used for rows limitation
+	UseTopClause bool
 }
 
 type where struct {
diff --git a/queries/query_builders.go b/queries/query_builders.go
index 683c6b5..1d22440 100644
--- a/queries/query_builders.go
+++ b/queries/query_builders.go
@@ -46,6 +46,12 @@ func buildSelectQuery(q *Query) (*bytes.Buffer, []interface{}) {
 
 	buf.WriteString("SELECT ")
 
+	if q.dialect.UseTopClause {
+		if q.limit != 0 && q.offset == 0 {
+			fmt.Fprintf(buf, " TOP (%d)", q.limit)
+		}
+	}
+
 	if q.count {
 		buf.WriteString("COUNT(")
 	}
@@ -308,11 +314,26 @@ func writeModifiers(q *Query, buf *bytes.Buffer, args *[]interface{}) {
 		buf.WriteString(strings.Join(q.orderBy, ", "))
 	}
 
-	if q.limit != 0 {
-		fmt.Fprintf(buf, " LIMIT %d", q.limit)
-	}
-	if q.offset != 0 {
-		fmt.Fprintf(buf, " OFFSET %d", q.offset)
+	if !q.dialect.UseTopClause {
+		if q.limit != 0 {
+			fmt.Fprintf(buf, " LIMIT %d", q.limit)
+		}
+
+		if q.offset != 0 {
+			fmt.Fprintf(buf, " OFFSET %d", q.offset)
+		}
+	} else {
+		// From MS SQL 2012 and above: https://technet.microsoft.com/en-us/library/ms188385(v=sql.110).aspx
+		// ORDER BY ...
+		// OFFSET N ROWS
+		// FETCH NEXT M ROWS ONLY
+		if q.offset != 0 {
+			fmt.Fprintf(buf, " OFFSET %d", q.offset)
+
+			if q.limit != 0 {
+				fmt.Fprintf(buf, " FETCH NEXT %d ROWS ONLY", q.limit)
+			}
+		}
 	}
 
 	if len(q.forlock) != 0 {

From b3c4580efafc99bfb25f6e9f51553db33d9a11a5 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 12:45:50 +0300
Subject: [PATCH 057/179] Fixed comment for SchemaTable

---
 strmangle/strmangle.go | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/strmangle/strmangle.go b/strmangle/strmangle.go
index 4dc0b1b..7881275 100644
--- a/strmangle/strmangle.go
+++ b/strmangle/strmangle.go
@@ -82,7 +82,8 @@ func init() {
 
 // SchemaTable returns a table name with a schema prefixed if
 // using a database that supports real schemas, for example,
-// for Postgres: "schema_name"."table_name", versus
+// for Postgres: "schema_name"."table_name",
+// for MS SQL: [schema_name].[table_name], versus
 // simply "table_name" for MySQL (because it does not support real schemas)
 func SchemaTable(lq, rq string, driver string, schema string, table string) string {
 	if (driver == "postgres" && schema != "public") || driver == "mssql" {

From 454a3a816a1a7a9e478cdd305084b97b73aaea01 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 13:46:35 +0300
Subject: [PATCH 058/179] Fixed quote symbols

---
 bdb/drivers/mssql.go | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 4e99e8c..271b337 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -347,15 +347,15 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 
 // RightQuote is the quoting character for the right side of the identifier
 func (m *MSSQLDriver) RightQuote() byte {
-	return '\''
+	return '"'
 }
 
 // LeftQuote is the quoting character for the left side of the identifier
 func (m *MSSQLDriver) LeftQuote() byte {
-	return '\''
+	return '"'
 }
 
-// IndexPlaceholders returns false to indicate MSSQL doesnt support indexed placeholders
+// IndexPlaceholders returns false to indicate MS SQL doesnt support indexed placeholders
 func (m *MSSQLDriver) IndexPlaceholders() bool {
 	return false
 }

From 83d90f3f28e63fd172fe8cb0ced83b6cc2341731 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 13:48:38 +0300
Subject: [PATCH 059/179] Fixed quote symbols order

---
 templates/15_insert.tpl | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index 5fea2c3..4833bef 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -66,7 +66,7 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 			return err
 		}
 		if len(wl) != 0 {
-			cache.query = fmt.Sprintf("INSERT INTO {{$schemaTable}} ({{.LQ}}%s{{.RQ}}) VALUES (%s)", strings.Join(wl, "{{.LQ}},{{.RQ}}"), strmangle.Placeholders(dialect.IndexPlaceholders, len(wl), 1, 1))
+			cache.query = fmt.Sprintf("INSERT INTO {{$schemaTable}} ({{.LQ}}%s{{.RQ}}) VALUES (%s)", strings.Join(wl, "{{.RQ}},{{.LQ}}"), strmangle.Placeholders(dialect.IndexPlaceholders, len(wl), 1, 1))
 		} else {
 			{{if eq .DriverName "mysql" -}}
 			cache.query = "INSERT INTO {{$schemaTable}} () VALUES ()"
@@ -77,9 +77,9 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 
 		if len(cache.retMapping) != 0 {
 			{{if .UseLastInsertID -}}
-			cache.retQuery = fmt.Sprintf("SELECT {{.LQ}}%s{{.RQ}} FROM {{$schemaTable}} WHERE %s", strings.Join(returnColumns, "{{.LQ}},{{.RQ}}"), strmangle.WhereClause("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns))
+			cache.retQuery = fmt.Sprintf("SELECT {{.LQ}}%s{{.RQ}} FROM {{$schemaTable}} WHERE %s", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"), strmangle.WhereClause("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns))
 			{{else -}}
-			cache.query += fmt.Sprintf(" RETURNING {{.LQ}}%s{{.RQ}}", strings.Join(returnColumns, "{{.LQ}},{{.RQ}}"))
+			cache.query += fmt.Sprintf(" RETURNING {{.LQ}}%s{{.RQ}}", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"))
 			{{end -}}
 		}
 	}

From ed6dad7eedd3e3b84f88a5291ce76c774f9821fd Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 13:53:35 +0300
Subject: [PATCH 060/179] MS SQL compatible query for checks if the row exists

---
 templates/20_exists.tpl | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/templates/20_exists.tpl b/templates/20_exists.tpl
index 3a9c693..22a67a0 100644
--- a/templates/20_exists.tpl
+++ b/templates/20_exists.tpl
@@ -6,8 +6,11 @@
 // {{$tableNameSingular}}Exists checks if the {{$tableNameSingular}} row exists.
 func {{$tableNameSingular}}Exists(exec boil.Executor, {{$pkArgs}}) (bool, error) {
 	var exists bool
-
+	{{if eq .DriverName "mssql" -}}
+	sql := "select case when exists(select top(1) 1 from {{$schemaTable}} where {{if .Dialect.IndexPlaceholders}}{{whereClause .LQ .RQ 1 .Table.PKey.Columns}}{{else}}{{whereClause .LQ .RQ 0 .Table.PKey.Columns}}{{end}}) then 1 else 0 end"
+	{{- else -}}
 	sql := "select exists(select 1 from {{$schemaTable}} where {{if .Dialect.IndexPlaceholders}}{{whereClause .LQ .RQ 1 .Table.PKey.Columns}}{{else}}{{whereClause .LQ .RQ 0 .Table.PKey.Columns}}{{end}} limit 1)"
+	{{- end}}
 
 	if boil.DebugMode {
 		fmt.Fprintln(boil.DebugWriter, sql)

From aa01f21b5c5f2e4e34df2238488564f28206f499 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 13:59:05 +0300
Subject: [PATCH 061/179] Pass UseTopClause flag into the Dialect object

---
 templates/singleton/boil_queries.tpl | 1 +
 1 file changed, 1 insertion(+)

diff --git a/templates/singleton/boil_queries.tpl b/templates/singleton/boil_queries.tpl
index d0879cb..3883e8e 100644
--- a/templates/singleton/boil_queries.tpl
+++ b/templates/singleton/boil_queries.tpl
@@ -2,6 +2,7 @@ var dialect = queries.Dialect{
 	LQ: 0x{{printf "%x" .Dialect.LQ}},
 	RQ: 0x{{printf "%x" .Dialect.RQ}},
 	IndexPlaceholders: {{.Dialect.IndexPlaceholders}},
+	UseTopClause: {{.Dialect.UseTopClause}},
 }
 
 // NewQueryG initializes a new Query using the passed in QueryMods

From e3254c185114c45c627e6f0f22ab552db04d2884 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 14:01:53 +0300
Subject: [PATCH 062/179] Allow MS SQL driver to use indexed placeholders

---
 bdb/drivers/mssql.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 271b337..fce6227 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -355,7 +355,7 @@ func (m *MSSQLDriver) LeftQuote() byte {
 	return '"'
 }
 
-// IndexPlaceholders returns false to indicate MS SQL doesnt support indexed placeholders
+// IndexPlaceholders returns true to indicate MS SQL supports indexed placeholders
 func (m *MSSQLDriver) IndexPlaceholders() bool {
-	return false
+	return true
 }

From b78331124809a3aa900da1116f67452182ccaa9f Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 14:24:03 +0300
Subject: [PATCH 063/179] Hack for MS SQL limit/offset query without ORDER BY
 clause

---
 queries/query_builders.go | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/queries/query_builders.go b/queries/query_builders.go
index 1d22440..6d798b3 100644
--- a/queries/query_builders.go
+++ b/queries/query_builders.go
@@ -328,6 +328,16 @@ func writeModifiers(q *Query, buf *bytes.Buffer, args *[]interface{}) {
 		// OFFSET N ROWS
 		// FETCH NEXT M ROWS ONLY
 		if q.offset != 0 {
+
+			// Hack from https://www.microsoftpressstore.com/articles/article.aspx?p=2314819
+			// ...
+			// As mentioned, the OFFSET-FETCH filter requires an ORDER BY clause. If you want to use arbitrary order,
+			// like TOP without an ORDER BY clause, you can use the trick with ORDER BY (SELECT NULL)
+			// ...
+			if len(q.orderBy) == 0 {
+				buf.WriteString(" ORDER BY (SELECT NULL)")
+			}
+
 			fmt.Fprintf(buf, " OFFSET %d", q.offset)
 
 			if q.limit != 0 {

From 4f02886c2b875d3e0d9869e0b77d59be2648591d Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 14:31:52 +0300
Subject: [PATCH 064/179] Added space in SELECT TOP clause

---
 queries/query_builders.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/queries/query_builders.go b/queries/query_builders.go
index 6d798b3..3136693 100644
--- a/queries/query_builders.go
+++ b/queries/query_builders.go
@@ -48,7 +48,7 @@ func buildSelectQuery(q *Query) (*bytes.Buffer, []interface{}) {
 
 	if q.dialect.UseTopClause {
 		if q.limit != 0 && q.offset == 0 {
-			fmt.Fprintf(buf, " TOP (%d)", q.limit)
+			fmt.Fprintf(buf, " TOP (%d) ", q.limit)
 		}
 	}
 

From 0bdbee86f1eb0a0a493d3de75570cfb0b4bb2c43 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 14:58:32 +0300
Subject: [PATCH 065/179] Queries refactoring

---
 bdb/drivers/mssql.go | 54 ++++++++++++++++++++++++--------------------
 1 file changed, 29 insertions(+), 25 deletions(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index fce6227..afdff66 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -80,15 +80,19 @@ func (m *MSSQLDriver) UseTopClause() bool {
 func (m *MSSQLDriver) TableNames(schema string, whitelist, blacklist []string) ([]string, error) {
 	var names []string
 
-	query := fmt.Sprintf(`select table_name from information_schema.tables where table_schema = ? and table_type = 'BASE TABLE'`)
+	query := `
+		SELECT table_name
+		FROM   information_schema.tables
+		WHERE  table_schema = ? AND table_type = 'BASE TABLE'`
+
 	args := []interface{}{schema}
 	if len(whitelist) > 0 {
-		query += fmt.Sprintf(" and table_name in (%s);", strings.Repeat(",?", len(whitelist))[1:])
+		query += fmt.Sprintf(" AND table_name IN (%s);", strings.Repeat(",?", len(whitelist))[1:])
 		for _, w := range whitelist {
 			args = append(args, w)
 		}
 	} else if len(blacklist) > 0 {
-		query += fmt.Sprintf(" and table_name not in (%s);", strings.Repeat(",?", len(blacklist))[1:])
+		query += fmt.Sprintf(" AND table_name not IN (%s);", strings.Repeat(",?", len(blacklist))[1:])
 		for _, b := range blacklist {
 			args = append(args, b)
 		}
@@ -122,13 +126,13 @@ func (m *MSSQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
 	rows, err := m.dbConn.Query(`
 	SELECT column_name,
        CASE
-         WHEN CHARACTER_MAXIMUM_LENGTH IS NULL THEN data_type
-         ELSE data_type + '(' + CAST(CHARACTER_MAXIMUM_LENGTH AS VARCHAR) + ')'
+         WHEN character_maximum_length IS NULL THEN data_type
+         ELSE data_type + '(' + CAST(character_maximum_length AS VARCHAR) + ')'
        END AS full_type,
        data_type,
 	   column_default,
        CASE
-         WHEN IS_NULLABLE = 'YES' THEN 1
+         WHEN is_nullable = 'YES' THEN 1
          ELSE 0
        END AS is_nullable,
        CASE
@@ -148,8 +152,8 @@ func (m *MSSQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
                              AND   constraint_name = tc.constraint_name) = 1) THEN 1
          ELSE 0
        END AS is_unique
-	FROM INFORMATION_SCHEMA.columns c
-	where table_name = ? and table_schema = ?;
+	FROM information_schema.columns c
+	WHERE table_name = ? AND table_schema = ?;
 	`, tableName, schema)
 
 	if err != nil {
@@ -189,9 +193,9 @@ func (m *MSSQLDriver) PrimaryKeyInfo(schema, tableName string) (*bdb.PrimaryKey,
 	var err error
 
 	query := `
-	select tc.constraint_name
-	from information_schema.table_constraints as tc
-	where tc.table_name = ? and tc.constraint_type = 'PRIMARY KEY' and tc.table_schema = ?;`
+	SELECT constraint_name
+	FROM   information_schema.table_constraints
+	WHERE  table_name = ? AND constraint_type = 'PRIMARY KEY' AND table_schema = ?;`
 
 	row := m.dbConn.QueryRow(query, tableName, schema)
 	if err = row.Scan(&pkey.Name); err != nil {
@@ -202,9 +206,9 @@ func (m *MSSQLDriver) PrimaryKeyInfo(schema, tableName string) (*bdb.PrimaryKey,
 	}
 
 	queryColumns := `
-	select kcu.column_name
-	from   information_schema.key_column_usage as kcu
-	where  table_name = ? and constraint_name = ? and table_schema = ?;`
+	SELECT column_name
+	FROM   information_schema.key_column_usage
+	WHERE  table_name = ? AND constraint_name = ? AND table_schema = ?;`
 
 	var rows *sql.Rows
 	if rows, err = m.dbConn.Query(queryColumns, tableName, pkey.Name, schema); err != nil {
@@ -239,17 +243,17 @@ func (m *MSSQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey
 
 	query := `
 	SELECT 
-		ccu.constraint_name AS SourceConstraint
-		,ccu.table_name AS SourceTable
-		,ccu.column_name AS SourceColumn
-		,kcu.table_name AS TargetTable
-		,kcu.column_name AS TargetColumn
-	FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE ccu
-    INNER JOIN INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS rc
-        ON ccu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME 
-    INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu 
-        ON kcu.CONSTRAINT_NAME = rc.UNIQUE_CONSTRAINT_NAME  
-	where ccu.table_schema = ? and ccu.constraint_schema = ? and ccu.table_name = ?
+		ccu.constraint_name
+		,ccu.table_name AS local_table
+		,ccu.column_name AS local_column
+		,kcu.table_name AS foreign_table
+		,kcu.column_name AS foreign_column
+	FROM information_schema.constraint_column_usage ccu
+    INNER JOIN information_schema.referential_constraints rc
+        ON ccu.constraint_name = rc.constraint_name 
+    INNER JOIN information_schema.key_column_usage kcu 
+        ON kcu.constraint_name = rc.unique_constraint_name  
+	WHERE ccu.table_schema = ? AND ccu.constraint_schema = ? AND ccu.table_name = ?
 	`
 
 	var rows *sql.Rows

From e2e619dfb2af0773ef721a2f54e16808cda80656 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 16:51:56 +0300
Subject: [PATCH 066/179] Check for error on tables schema file opening

---
 templates_test/main_test/mssql_main.tpl | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/templates_test/main_test/mssql_main.tpl b/templates_test/main_test/mssql_main.tpl
index 82acbfc..a164819 100644
--- a/templates_test/main_test/mssql_main.tpl
+++ b/templates_test/main_test/mssql_main.tpl
@@ -33,7 +33,12 @@ func (m *mssqlTester) setup() error {
 
 	createCmd := exec.Command("sqlcmd", "-S", m.host, "-U", m.user, "-P", m.pass, "-d", m.testDBName)
 
-	f, err := os.Open("tables.sql")
+	f, err := os.Open("tables_schema.sql")
+
+	if err != nil {
+		return errors.Wrap(err, "failed to open tables_schema.sql file")
+	}
+
 	defer f.Close()
 
 	createCmd.Stdin = newFKeyDestroyer(rgxMSSQLkey, f)

From a48e5f7f82bb51bd6eea068ff1821b1b04a6ab85 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 16:52:54 +0300
Subject: [PATCH 067/179] MS SQL compatible query for RETURNING clause

---
 templates/15_insert.tpl | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index 4833bef..4906875 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -79,7 +79,11 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 			{{if .UseLastInsertID -}}
 			cache.retQuery = fmt.Sprintf("SELECT {{.LQ}}%s{{.RQ}} FROM {{$schemaTable}} WHERE %s", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"), strmangle.WhereClause("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns))
 			{{else -}}
+				{{if ne .DriverName "mssql" -}}
 			cache.query += fmt.Sprintf(" RETURNING {{.LQ}}%s{{.RQ}}", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"))
+				{{- else -}}
+			cache.query += fmt.Sprintf(" OUTPUT {{.LQ}}%s{{.RQ}}", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"))
+				{{- end}}
 			{{end -}}
 		}
 	}

From 813fd43e035a593e3a01dde9077218ae6307b906 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 17:41:45 +0300
Subject: [PATCH 068/179] Ignore columns with defaults on Insert

---
 templates_test/delete.tpl | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/templates_test/delete.tpl b/templates_test/delete.tpl
index f745ea4..d548efa 100644
--- a/templates_test/delete.tpl
+++ b/templates_test/delete.tpl
@@ -8,7 +8,7 @@ func test{{$tableNamePlural}}Delete(t *testing.T) {
 	seed := randomize.NewSeed()
 	var err error
 	{{$varNameSingular}} := &{{$tableNameSingular}}{}
-	if err = randomize.Struct(seed, {{$varNameSingular}}, {{$varNameSingular}}DBTypes, true); err != nil {
+	if err = randomize.Struct(seed, {{$varNameSingular}}, {{$varNameSingular}}DBTypes, true, {{$varNameSingular}}ColumnsWithDefault...); err != nil {
 		t.Errorf("Unable to randomize {{$tableNameSingular}} struct: %s", err)
 	}
 
@@ -38,7 +38,7 @@ func test{{$tableNamePlural}}QueryDeleteAll(t *testing.T) {
 	seed := randomize.NewSeed()
 	var err error
 	{{$varNameSingular}} := &{{$tableNameSingular}}{}
-	if err = randomize.Struct(seed, {{$varNameSingular}}, {{$varNameSingular}}DBTypes, true); err != nil {
+	if err = randomize.Struct(seed, {{$varNameSingular}}, {{$varNameSingular}}DBTypes, true, {{$varNameSingular}}ColumnsWithDefault...); err != nil {
 		t.Errorf("Unable to randomize {{$tableNameSingular}} struct: %s", err)
 	}
 
@@ -68,7 +68,7 @@ func test{{$tableNamePlural}}SliceDeleteAll(t *testing.T) {
 	seed := randomize.NewSeed()
 	var err error
 	{{$varNameSingular}} := &{{$tableNameSingular}}{}
-	if err = randomize.Struct(seed, {{$varNameSingular}}, {{$varNameSingular}}DBTypes, true); err != nil {
+	if err = randomize.Struct(seed, {{$varNameSingular}}, {{$varNameSingular}}DBTypes, true, {{$varNameSingular}}ColumnsWithDefault...); err != nil {
 		t.Errorf("Unable to randomize {{$tableNameSingular}} struct: %s", err)
 	}
 

From 5d725696357fb3752dde791677cb2d405d0ce282 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 18:06:12 +0300
Subject: [PATCH 069/179] Fixed Insert and Select for timestamp, rowversion

---
 bdb/drivers/mssql.go | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index afdff66..9b14e38 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -177,10 +177,13 @@ func (m *MSSQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
 			Unique:     unique,
 		}
 
-		if defaultValue != nil && *defaultValue != "NULL" {
+		// Hack to exclude columns with types timestamp and rowversion from inserts
+		// Values for this columns provides by SQL Server on Insert clause
+		if (strings.EqualFold(colType, "timestamp") || strings.EqualFold(colType, "rowversion")) && defaultValue == nil {
+			column.Default = colType
+		} else if defaultValue != nil && *defaultValue != "NULL" {
 			column.Default = *defaultValue
 		}
-
 		columns = append(columns, column)
 	}
 
@@ -306,12 +309,12 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			c.Type = "null.Float64"
 		case "boolean", "bool":
 			c.Type = "null.Bool"
-		case "date", "datetime", "timestamp", "time":
+		case "date", "datetime", "time":
 			c.Type = "null.Time"
 		case "binary", "varbinary", "tinyblob", "blob", "mediumblob", "longblob":
 			c.Type = "null.Bytes"
-		case "json":
-			c.Type = "types.JSON"
+		case "timestamp", "rowversion":
+			c.Type = "null.Bytes"
 		default:
 			c.Type = "null.String"
 		}
@@ -335,12 +338,12 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			c.Type = "float64"
 		case "boolean", "bool":
 			c.Type = "bool"
-		case "date", "datetime", "timestamp", "time":
+		case "date", "datetime", "time":
 			c.Type = "time.Time"
 		case "binary", "varbinary", "tinyblob", "blob", "mediumblob", "longblob":
 			c.Type = "[]byte"
-		case "json":
-			c.Type = "types.JSON"
+		case "timestamp", "rowversion":
+			c.Type = "[]byte"
 		default:
 			c.Type = "string"
 		}

From 51e9961f0a7918a296277a17c2a6f55d8ac1e590 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 18:06:33 +0300
Subject: [PATCH 070/179] Fixed OUTPUT values on Insert

---
 templates/15_insert.tpl | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index 4906875..53c2677 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -66,7 +66,15 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 			return err
 		}
 		if len(wl) != 0 {
+			{{if ne .DriverName "mssql" -}}
 			cache.query = fmt.Sprintf("INSERT INTO {{$schemaTable}} ({{.LQ}}%s{{.RQ}}) VALUES (%s)", strings.Join(wl, "{{.RQ}},{{.LQ}}"), strmangle.Placeholders(dialect.IndexPlaceholders, len(wl), 1, 1))
+			{{- else -}}
+			if len(cache.retMapping) == 0 {
+				cache.query = fmt.Sprintf("INSERT INTO {{$schemaTable}} ({{.LQ}}%s{{.RQ}}) VALUES (%s)", strings.Join(wl, "{{.RQ}},{{.LQ}}"), strmangle.Placeholders(dialect.IndexPlaceholders, len(wl), 1, 1))			
+			} else {
+				cache.query = fmt.Sprintf("INSERT INTO {{$schemaTable}} ({{.LQ}}%s{{.RQ}}) OUTPUT INSERTED.{{.LQ}}%s{{.RQ}} VALUES (%s)", strings.Join(wl, "{{.RQ}},{{.LQ}}"), strings.Join(returnColumns, "{{.RQ}},INSERTED.{{.LQ}}"), strmangle.Placeholders(dialect.IndexPlaceholders, len(wl), 1, 1))			
+			}
+			{{- end}}
 		} else {
 			{{if eq .DriverName "mysql" -}}
 			cache.query = "INSERT INTO {{$schemaTable}} () VALUES ()"
@@ -75,17 +83,15 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 			{{end -}}
 		}
 
+		{{if ne .DriverName "mssql" -}}
 		if len(cache.retMapping) != 0 {
 			{{if .UseLastInsertID -}}
 			cache.retQuery = fmt.Sprintf("SELECT {{.LQ}}%s{{.RQ}} FROM {{$schemaTable}} WHERE %s", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"), strmangle.WhereClause("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns))
-			{{else -}}
-				{{if ne .DriverName "mssql" -}}
+			{{else -}}	
 			cache.query += fmt.Sprintf(" RETURNING {{.LQ}}%s{{.RQ}}", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"))
-				{{- else -}}
-			cache.query += fmt.Sprintf(" OUTPUT {{.LQ}}%s{{.RQ}}", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"))
-				{{- end}}
-			{{end -}}
+			{{- end}}
 		}
+		{{end -}}
 	}
 
 	value := reflect.Indirect(reflect.ValueOf(o))

From 6aadf439c9d5dc1ffda6e1619827d8fef6714e56 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 18:45:41 +0300
Subject: [PATCH 071/179] Fixed column types mapping

---
 bdb/drivers/mssql.go | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 9b14e38..a36a3eb 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -305,13 +305,13 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			c.Type = "null.Int64"
 		case "float":
 			c.Type = "null.Float32"
-		case "double", "double precision", "real":
+		case "real":
 			c.Type = "null.Float64"
 		case "boolean", "bool":
 			c.Type = "null.Bool"
-		case "date", "datetime", "time":
+		case "date", "datetime", "datetime2", "smalldatetime", "time":
 			c.Type = "null.Time"
-		case "binary", "varbinary", "tinyblob", "blob", "mediumblob", "longblob":
+		case "binary", "varbinary":
 			c.Type = "null.Bytes"
 		case "timestamp", "rowversion":
 			c.Type = "null.Bytes"
@@ -334,13 +334,13 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			c.Type = "int64"
 		case "float":
 			c.Type = "float32"
-		case "double", "double precision", "real":
+		case "real":
 			c.Type = "float64"
 		case "boolean", "bool":
 			c.Type = "bool"
-		case "date", "datetime", "time":
+		case "date", "datetime", "datetime2", "smalldatetime", "time":
 			c.Type = "time.Time"
-		case "binary", "varbinary", "tinyblob", "blob", "mediumblob", "longblob":
+		case "binary", "varbinary":
 			c.Type = "[]byte"
 		case "timestamp", "rowversion":
 			c.Type = "[]byte"

From 85fc6e546a009e8ef8cf420a8918ea732970a6cb Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 14 Mar 2017 18:49:40 +0300
Subject: [PATCH 072/179] Fixed float and real mapping

---
 bdb/drivers/mssql.go | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index a36a3eb..502ff51 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -303,9 +303,9 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			c.Type = "null.Int"
 		case "bigint":
 			c.Type = "null.Int64"
-		case "float":
-			c.Type = "null.Float32"
 		case "real":
+			c.Type = "null.Float32"
+		case "float":
 			c.Type = "null.Float64"
 		case "boolean", "bool":
 			c.Type = "null.Bool"
@@ -332,9 +332,9 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			c.Type = "int"
 		case "bigint":
 			c.Type = "int64"
-		case "float":
-			c.Type = "float32"
 		case "real":
+			c.Type = "float32"
+		case "float":
 			c.Type = "float64"
 		case "boolean", "bool":
 			c.Type = "bool"

From 705befef070ac934034e984166dd7a71fd4d281d Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Wed, 15 Mar 2017 14:12:21 +0300
Subject: [PATCH 073/179] Fixed types mapping

---
 bdb/drivers/mssql.go | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 502ff51..920ce09 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -291,15 +291,13 @@ func (m *MSSQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey
 func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 	if c.Nullable {
 		switch c.DBType {
-		case "bit":
-			c.Type = "bool"
 		case "tinyint":
-			c.Type = "int8"
+			c.Type = "null.Int8"
 		case "smallint":
 			c.Type = "null.Int16"
 		case "mediumint":
 			c.Type = "null.Int32"
-		case "int", "integer":
+		case "int":
 			c.Type = "null.Int"
 		case "bigint":
 			c.Type = "null.Int64"
@@ -307,7 +305,7 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			c.Type = "null.Float32"
 		case "float":
 			c.Type = "null.Float64"
-		case "boolean", "bool":
+		case "boolean", "bool", "bit":
 			c.Type = "null.Bool"
 		case "date", "datetime", "datetime2", "smalldatetime", "time":
 			c.Type = "null.Time"
@@ -320,15 +318,13 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 		}
 	} else {
 		switch c.DBType {
-		case "bit":
-			c.Type = "bool"
 		case "tinyint":
 			c.Type = "int8"
 		case "smallint":
 			c.Type = "int16"
 		case "mediumint":
 			c.Type = "int32"
-		case "int", "integer":
+		case "int":
 			c.Type = "int"
 		case "bigint":
 			c.Type = "int64"
@@ -336,7 +332,7 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			c.Type = "float32"
 		case "float":
 			c.Type = "float64"
-		case "boolean", "bool":
+		case "boolean", "bool", "bit":
 			c.Type = "bool"
 		case "date", "datetime", "datetime2", "smalldatetime", "time":
 			c.Type = "time.Time"

From 6fad1bd148b9231c075ba7249b3ce77a05b2715c Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Wed, 15 Mar 2017 15:31:09 +0300
Subject: [PATCH 074/179] Added column flag for autogenerated values like
 IDENTITY | TIMESTAMP | ROWVERSION

---
 bdb/column.go        |  7 ++++++-
 bdb/drivers/mssql.go | 30 +++++++++++++++---------------
 2 files changed, 21 insertions(+), 16 deletions(-)

diff --git a/bdb/column.go b/bdb/column.go
index 5ed7a8b..9ce4bc4 100644
--- a/bdb/column.go
+++ b/bdb/column.go
@@ -29,6 +29,11 @@ type Column struct {
 	// tinyint(1) instead of tinyint
 	// Used for "tinyint-as-bool" flag
 	FullDBType string
+
+	// MS SQL only bits
+	// Used to indicate that the value
+	// for this column is auto generated by database on insert (i.e. - timestamp (old) or rowversion (new))
+	AutoGenerated bool
 }
 
 // ColumnNames of the columns.
@@ -57,7 +62,7 @@ func FilterColumnsByDefault(defaults bool, columns []Column) []Column {
 	var cols []Column
 
 	for _, c := range columns {
-		if (defaults && len(c.Default) != 0) || (!defaults && len(c.Default) == 0) {
+		if (defaults && (len(c.Default) != 0 || c.AutoGenerated)) || (!defaults && len(c.Default) == 0 && !c.AutoGenerated) {
 			cols = append(cols, c)
 		}
 	}
diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 920ce09..254f68d 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -151,10 +151,11 @@ func (m *MSSQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
                              AND   table_name = tc.table_name
                              AND   constraint_name = tc.constraint_name) = 1) THEN 1
          ELSE 0
-       END AS is_unique
+       END AS is_unique,
+	   COLUMNPROPERTY(object_id($1 + '.' + $2), c.column_name, 'IsIdentity') as is_identity
 	FROM information_schema.columns c
-	WHERE table_name = ? AND table_schema = ?;
-	`, tableName, schema)
+	WHERE table_schema = $1 AND table_name = $2;
+	`, schema, tableName)
 
 	if err != nil {
 		return nil, err
@@ -163,25 +164,24 @@ func (m *MSSQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
 
 	for rows.Next() {
 		var colName, colType, colFullType string
-		var nullable, unique bool
+		var nullable, unique, identity, auto bool
 		var defaultValue *string
-		if err := rows.Scan(&colName, &colFullType, &colType, &defaultValue, &nullable, &unique); err != nil {
+		if err := rows.Scan(&colName, &colFullType, &colType, &defaultValue, &nullable, &unique, &identity); err != nil {
 			return nil, errors.Wrapf(err, "unable to scan for table %s", tableName)
 		}
 
+		auto = identity || strings.EqualFold(colType, "timestamp") || strings.EqualFold(colType, "rowversion")
+
 		column := bdb.Column{
-			Name:       colName,
-			FullDBType: colFullType, // example: tinyint(1) instead of tinyint
-			DBType:     colType,
-			Nullable:   nullable,
-			Unique:     unique,
+			Name:          colName,
+			FullDBType:    colFullType,
+			DBType:        colType,
+			Nullable:      nullable,
+			Unique:        unique,
+			AutoGenerated: auto,
 		}
 
-		// Hack to exclude columns with types timestamp and rowversion from inserts
-		// Values for this columns provides by SQL Server on Insert clause
-		if (strings.EqualFold(colType, "timestamp") || strings.EqualFold(colType, "rowversion")) && defaultValue == nil {
-			column.Default = colType
-		} else if defaultValue != nil && *defaultValue != "NULL" {
+		if defaultValue != nil && *defaultValue != "NULL" {
 			column.Default = *defaultValue
 		}
 		columns = append(columns, column)

From 54f960659b66215ed88ebda07aef50bb1cbe6c9b Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Wed, 15 Mar 2017 15:37:04 +0300
Subject: [PATCH 075/179] Ignore columns with defaults in randomize

---
 templates_test/update.tpl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/templates_test/update.tpl b/templates_test/update.tpl
index b33854d..2612a87 100644
--- a/templates_test/update.tpl
+++ b/templates_test/update.tpl
@@ -12,7 +12,7 @@ func test{{$tableNamePlural}}Update(t *testing.T) {
 	seed := randomize.NewSeed()
 	var err error
 	{{$varNameSingular}} := &{{$tableNameSingular}}{}
-	if err = randomize.Struct(seed, {{$varNameSingular}}, {{$varNameSingular}}DBTypes, true); err != nil {
+	if err = randomize.Struct(seed, {{$varNameSingular}}, {{$varNameSingular}}DBTypes, true, {{$varNameSingular}}ColumnsWithDefault...); err != nil {
 		t.Errorf("Unable to randomize {{$tableNameSingular}} struct: %s", err)
 	}
 
@@ -50,7 +50,7 @@ func test{{$tableNamePlural}}SliceUpdateAll(t *testing.T) {
 	seed := randomize.NewSeed()
 	var err error
 	{{$varNameSingular}} := &{{$tableNameSingular}}{}
-	if err = randomize.Struct(seed, {{$varNameSingular}}, {{$varNameSingular}}DBTypes, true); err != nil {
+	if err = randomize.Struct(seed, {{$varNameSingular}}, {{$varNameSingular}}DBTypes, true, {{$varNameSingular}}ColumnsWithDefault...); err != nil {
 		t.Errorf("Unable to randomize {{$tableNameSingular}} struct: %s", err)
 	}
 

From bfab02bde166b8c972f5a066ea1ace8988d821f7 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Wed, 15 Mar 2017 18:02:56 +0300
Subject: [PATCH 076/179] WhereClauseRepeated func for repeated Where clause

---
 strmangle/strmangle.go | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/strmangle/strmangle.go b/strmangle/strmangle.go
index 7881275..b5b68cb 100644
--- a/strmangle/strmangle.go
+++ b/strmangle/strmangle.go
@@ -521,6 +521,37 @@ func WhereClause(lq, rq string, start int, cols []string) string {
 	return buf.String()
 }
 
+// WhereClauseRepeated returns the where clause repeated with OR clause using start as the $ flag index
+// For example, if start was 2 output would be: "(colthing=$2 AND colstuff=$3) OR (colthing=$4 AND colstuff=$5)"
+func WhereClauseRepeated(lq, rq string, start int, cols []string, count int) string {
+
+	var startIndex int
+
+	buf := GetBuffer()
+	defer PutBuffer(buf)
+
+	buf.WriteByte('(')
+
+	for i := 0; i < count; i++ {
+
+		if i != 0 {
+			buf.WriteString(") OR (")
+		}
+
+		if start > 0 {
+			startIndex = start + i*len(cols)
+		} else {
+			startIndex = 0
+		}
+
+		buf.WriteString(WhereClause(lq, rq, startIndex, cols))
+	}
+
+	buf.WriteByte(')')
+
+	return buf.String()
+}
+
 // JoinSlices merges two string slices of equal length
 func JoinSlices(sep string, a, b []string) []string {
 	lna, lnb := len(a), len(b)

From ad15668462c060cdfb7e10ae2fc1dc5d3a678eda Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Wed, 15 Mar 2017 19:04:13 +0300
Subject: [PATCH 077/179] Fixed code generation

---
 templates/02_hooks.tpl                        |  6 +++---
 templates/18_delete.tpl                       | 11 +++++++++++
 templates_test/hooks.tpl                      |  2 +-
 templates_test/singleton/boil_suites_test.tpl |  2 +-
 4 files changed, 16 insertions(+), 5 deletions(-)

diff --git a/templates/02_hooks.tpl b/templates/02_hooks.tpl
index 073c8e9..073f8ec 100644
--- a/templates/02_hooks.tpl
+++ b/templates/02_hooks.tpl
@@ -4,7 +4,7 @@
 var {{$varNameSingular}}BeforeInsertHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}BeforeUpdateHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}BeforeDeleteHooks []{{$tableNameSingular}}Hook
-{{- if ne .DriverName "mssql" -}}
+{{if ne .DriverName "mssql" -}}
 var {{$varNameSingular}}BeforeUpsertHooks []{{$tableNameSingular}}Hook
 {{- end}}
 
@@ -12,7 +12,7 @@ var {{$varNameSingular}}AfterInsertHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}AfterSelectHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}AfterUpdateHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}AfterDeleteHooks []{{$tableNameSingular}}Hook
-{{- if ne .DriverName "mssql" -}}
+{{if ne .DriverName "mssql" -}}
 var {{$varNameSingular}}AfterUpsertHooks []{{$tableNameSingular}}Hook
 {{- end}}
 
@@ -140,7 +140,7 @@ func Add{{$tableNameSingular}}Hook(hookPoint boil.HookPoint, {{$varNameSingular}
 			{{$varNameSingular}}AfterUpdateHooks = append({{$varNameSingular}}AfterUpdateHooks, {{$varNameSingular}}Hook)
 		case boil.AfterDeleteHook:
 			{{$varNameSingular}}AfterDeleteHooks = append({{$varNameSingular}}AfterDeleteHooks, {{$varNameSingular}}Hook)
-		{{- if ne .DriverName "mssql" -}}
+		{{if ne .DriverName "mssql" -}}
 		case boil.AfterUpsertHook:
 			{{$varNameSingular}}AfterUpsertHooks = append({{$varNameSingular}}AfterUpsertHooks, {{$varNameSingular}}Hook)
 		{{- end}}
diff --git a/templates/18_delete.tpl b/templates/18_delete.tpl
index c34822e..317ae19 100644
--- a/templates/18_delete.tpl
+++ b/templates/18_delete.tpl
@@ -135,11 +135,22 @@ func (o {{$tableNameSingular}}Slice) DeleteAll(exec boil.Executor) error {
 		args = append(args, pkeyArgs...)
 	}
 
+	{{if ne .DriverName "mssql" -}}
 	sql := fmt.Sprintf(
 		"DELETE FROM {{$schemaTable}} WHERE (%s) IN (%s)",
 		strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, {{$varNameSingular}}PrimaryKeyColumns), ","),
 		strmangle.Placeholders(dialect.IndexPlaceholders, len(o) * len({{$varNameSingular}}PrimaryKeyColumns), 1, len({{$varNameSingular}}PrimaryKeyColumns)),
 	)
+	{{- else -}}
+	startIndex := 1
+
+	if dialect.IndexPlaceholders {
+		startIndex = 0
+	}
+
+	sql := "DELETE FROM {{$schemaTable}}  WHERE " +
+		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), startIndex, {{$varNameSingular}}PrimaryKeyColumns, len(o))
+	{{- end}}
 
 	if boil.DebugMode {
 		fmt.Fprintln(boil.DebugWriter, sql)
diff --git a/templates_test/hooks.tpl b/templates_test/hooks.tpl
index 9f11698..412ab0c 100644
--- a/templates_test/hooks.tpl
+++ b/templates_test/hooks.tpl
@@ -126,7 +126,7 @@ func test{{$tableNamePlural}}Hooks(t *testing.T) {
 	}
 	{{$varNameSingular}}AfterDeleteHooks = []{{$tableNameSingular}}Hook{}
 
-	{{- if ne .DriverName "mssql" -}}
+	{{if ne .DriverName "mssql" -}}
 	Add{{$tableNameSingular}}Hook(boil.BeforeUpsertHook, {{$varNameSingular}}BeforeUpsertHook)
 	if err = o.doBeforeUpsertHooks(nil); err != nil {
 		t.Errorf("Unable to execute doBeforeUpsertHooks: %s", err)
diff --git a/templates_test/singleton/boil_suites_test.tpl b/templates_test/singleton/boil_suites_test.tpl
index c1c3516..022d7be 100644
--- a/templates_test/singleton/boil_suites_test.tpl
+++ b/templates_test/singleton/boil_suites_test.tpl
@@ -327,7 +327,7 @@ func TestSliceUpdateAll(t *testing.T) {
   {{end -}}
   {{- end -}}
 }
-{{- if ne .DriverName "mssql" -}}
+{{if ne .DriverName "mssql" -}}
 func TestUpsert(t *testing.T) {
   {{- range $index, $table := .Tables}}
   {{- if $table.IsJoinTable -}}

From f45f98ef03c2ede2c2107c1244f17fd6841540ac Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Wed, 15 Mar 2017 19:13:20 +0300
Subject: [PATCH 078/179] Fixed placeholders

---
 templates/18_delete.tpl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/templates/18_delete.tpl b/templates/18_delete.tpl
index 317ae19..61282aa 100644
--- a/templates/18_delete.tpl
+++ b/templates/18_delete.tpl
@@ -144,7 +144,7 @@ func (o {{$tableNameSingular}}Slice) DeleteAll(exec boil.Executor) error {
 	{{- else -}}
 	startIndex := 1
 
-	if dialect.IndexPlaceholders {
+	if !dialect.IndexPlaceholders {
 		startIndex = 0
 	}
 

From 4c2062caee7d29bb7342ad6f13d6512e95ca2fc5 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Wed, 15 Mar 2017 19:35:44 +0300
Subject: [PATCH 079/179] Fixed code generation for Update and Reload

---
 templates/16_update.tpl | 13 ++++++++++++-
 templates/19_reload.tpl | 11 +++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index f84a35c..6dd8690 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -157,12 +157,23 @@ func (o {{$tableNameSingular}}Slice) UpdateAll(exec boil.Executor, cols M) error
 		pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), {{$varNameSingular}}PrimaryKeyMapping)
 		args = append(args, pkeyArgs...)
 	}
-
+	{{if ne .DriverName "mssql" -}}
 	sql := fmt.Sprintf(
 		"UPDATE {{$schemaTable}} SET %s WHERE ({{.LQ}}{{.Table.PKey.Columns | join (printf "%s,%s" .LQ .RQ)}}{{.RQ}}) IN (%s)",
 		strmangle.SetParamNames("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, colNames),
 		strmangle.Placeholders(dialect.IndexPlaceholders, len(o) * len({{$varNameSingular}}PrimaryKeyColumns), len(colNames)+1, len({{$varNameSingular}}PrimaryKeyColumns)),
 	)
+	{{- else -}}
+	startIndex := len(colNames) + 1
+
+	if !dialect.IndexPlaceholders {
+		startIndex = 0
+	}
+
+	sql := fmt.Sprintf("UPDATE {{$schemaTable}} SET %s WHERE %s",
+		strmangle.SetParamNames("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, colNames),
+		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), startIndex, {{$varNameSingular}}PrimaryKeyColumns, len(o)))
+	{{- end}}
 
 	if boil.DebugMode {
 		fmt.Fprintln(boil.DebugWriter, sql)
diff --git a/templates/19_reload.tpl b/templates/19_reload.tpl
index 45c0e61..ff656f1 100644
--- a/templates/19_reload.tpl
+++ b/templates/19_reload.tpl
@@ -79,11 +79,22 @@ func (o *{{$tableNameSingular}}Slice) ReloadAll(exec boil.Executor) error {
 		args = append(args, pkeyArgs...)
 	}
 
+	{{if ne .DriverName "mssql" -}}
 	sql := fmt.Sprintf(
 		"SELECT {{$schemaTable}}.* FROM {{$schemaTable}} WHERE (%s) IN (%s)",
 		strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, {{$varNameSingular}}PrimaryKeyColumns), ","),
 		strmangle.Placeholders(dialect.IndexPlaceholders, len(*o) * len({{$varNameSingular}}PrimaryKeyColumns), 1, len({{$varNameSingular}}PrimaryKeyColumns)),
 	)
+	{{- else -}}
+	startIndex := 1
+
+	if !dialect.IndexPlaceholders {
+		startIndex = 0
+	}
+
+	sql := "SELECT {{$schemaTable}}.* FROM {{$schemaTable}} WHERE " +
+		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), startIndex, {{$varNameSingular}}PrimaryKeyColumns, len(*o))
+	{{- end}}
 
 	q := queries.Raw(exec, sql, args...)
 

From 0a50c90a58a68f3014068477d2bab5d99d4b69f4 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Thu, 16 Mar 2017 09:55:50 +0300
Subject: [PATCH 080/179] Fixed test for MS SQL for columns with IDENTITY

---
 templates_test/insert.tpl | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/templates_test/insert.tpl b/templates_test/insert.tpl
index d14a0c8..82f87b6 100644
--- a/templates_test/insert.tpl
+++ b/templates_test/insert.tpl
@@ -41,7 +41,11 @@ func test{{$tableNamePlural}}InsertWhitelist(t *testing.T) {
 
 	tx := MustTx(boil.Begin())
 	defer tx.Rollback()
+	{{if ne .DriverName "mssql"}}
 	if err = {{$varNameSingular}}.Insert(tx, {{$varNameSingular}}Columns...); err != nil {
+	{{- else -}}
+	if err = {{$varNameSingular}}.Insert(tx, {{$varNameSingular}}ColumnsWithoutDefault...); err != nil {
+	{{- end}}
 		t.Error(err)
 	}
 

From e943c37a9929603def8e4fcfdac98ef900545507 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Thu, 16 Mar 2017 10:26:05 +0300
Subject: [PATCH 081/179] Update and Insert only for columns without
 autogenerated

---
 bdb/column.go            | 13 +++++++++++++
 boilingcore/templates.go |  1 +
 templates/01_types.tpl   |  1 +
 templates/15_insert.tpl  |  2 +-
 templates/16_update.tpl  |  2 +-
 5 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/bdb/column.go b/bdb/column.go
index 9ce4bc4..d33e0cb 100644
--- a/bdb/column.go
+++ b/bdb/column.go
@@ -57,6 +57,19 @@ func ColumnDBTypes(cols []Column) map[string]string {
 	return types
 }
 
+// FilterColumnsByAuto generates the list of columns that have autogenerated values
+func FilterColumnsByAuto(auto bool, columns []Column) []Column {
+	var cols []Column
+
+	for _, c := range columns {
+		if (auto && c.AutoGenerated) || (!auto && !c.AutoGenerated) {
+			cols = append(cols, c)
+		}
+	}
+
+	return cols
+}
+
 // FilterColumnsByDefault generates the list of columns that have default values
 func FilterColumnsByDefault(defaults bool, columns []Column) []Column {
 	var cols []Column
diff --git a/boilingcore/templates.go b/boilingcore/templates.go
index dec57bb..9c60739 100644
--- a/boilingcore/templates.go
+++ b/boilingcore/templates.go
@@ -225,6 +225,7 @@ var templateFunctions = template.FuncMap{
 	"txtsFromToMany":   txtsFromToMany,
 
 	// dbdrivers ops
+	"filterColumnsByAuto":    bdb.FilterColumnsByAuto,
 	"filterColumnsByDefault": bdb.FilterColumnsByDefault,
 	"filterColumnsByEnum":    bdb.FilterColumnsByEnum,
 	"sqlColDefinitions":      bdb.SQLColDefinitions,
diff --git a/templates/01_types.tpl b/templates/01_types.tpl
index ff497df..2631593 100644
--- a/templates/01_types.tpl
+++ b/templates/01_types.tpl
@@ -4,6 +4,7 @@
 {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
 var (
 	{{$varNameSingular}}Columns               = []string{{"{"}}{{.Table.Columns | columnNames | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}}
+	{{$varNameSingular}}ColumnsWithoutAuto = []string{{"{"}}{{.Table.Columns | filterColumnsByAuto false | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
 	{{$varNameSingular}}ColumnsWithoutDefault = []string{{"{"}}{{.Table.Columns | filterColumnsByDefault false | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
 	{{$varNameSingular}}ColumnsWithDefault    = []string{{"{"}}{{.Table.Columns | filterColumnsByDefault true | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
 	{{$varNameSingular}}PrimaryKeyColumns     = []string{{"{"}}{{.Table.PKey.Columns | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}}
diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index 53c2677..b07ef90 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -50,7 +50,7 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 
 	if !cached {
 		wl, returnColumns := strmangle.InsertColumnSet(
-			{{$varNameSingular}}Columns,
+			{{$varNameSingular}}ColumnsWithoutAuto,
 			{{$varNameSingular}}ColumnsWithDefault,
 			{{$varNameSingular}}ColumnsWithoutDefault,
 			nzDefaults,
diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index 6dd8690..aa3a3d9 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -48,7 +48,7 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 	{{$varNameSingular}}UpdateCacheMut.RUnlock()
 
 	if !cached {
-		wl := strmangle.UpdateColumnSet({{$varNameSingular}}Columns, {{$varNameSingular}}PrimaryKeyColumns, whitelist)
+		wl := strmangle.UpdateColumnSet({{$varNameSingular}}ColumnsWithoutAuto, {{$varNameSingular}}PrimaryKeyColumns, whitelist)
 		{{- if not .NoAutoTimestamps}}
 		if len(whitelist) == 0 {
 			wl = strmangle.SetComplement(wl, []string{"created_at"})

From 8de60ee26a4ff5877123de18730f4d54facbaa69 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Thu, 16 Mar 2017 10:54:55 +0300
Subject: [PATCH 082/179] Update and Insert for columns with autogenerated
 values

---
 templates/01_types.tpl    |  2 ++
 templates/15_insert.tpl   |  4 ++++
 templates/16_update.tpl   | 10 +++++++++-
 templates_test/update.tpl |  4 ++++
 4 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/templates/01_types.tpl b/templates/01_types.tpl
index 2631593..32a5d41 100644
--- a/templates/01_types.tpl
+++ b/templates/01_types.tpl
@@ -4,7 +4,9 @@
 {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
 var (
 	{{$varNameSingular}}Columns               = []string{{"{"}}{{.Table.Columns | columnNames | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}}
+	{{if eq .DriverName "mssql" -}}
 	{{$varNameSingular}}ColumnsWithoutAuto = []string{{"{"}}{{.Table.Columns | filterColumnsByAuto false | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
+	{{- end}}
 	{{$varNameSingular}}ColumnsWithoutDefault = []string{{"{"}}{{.Table.Columns | filterColumnsByDefault false | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
 	{{$varNameSingular}}ColumnsWithDefault    = []string{{"{"}}{{.Table.Columns | filterColumnsByDefault true | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
 	{{$varNameSingular}}PrimaryKeyColumns     = []string{{"{"}}{{.Table.PKey.Columns | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}}
diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index b07ef90..ade915a 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -50,7 +50,11 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 
 	if !cached {
 		wl, returnColumns := strmangle.InsertColumnSet(
+			{{if ne .DriverName "mssql" -}}
+			{{$varNameSingular}}Columns,
+			{{- else -}}
 			{{$varNameSingular}}ColumnsWithoutAuto,
+			{{- end}}
 			{{$varNameSingular}}ColumnsWithDefault,
 			{{$varNameSingular}}ColumnsWithoutDefault,
 			nzDefaults,
diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index aa3a3d9..f9eef64 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -48,7 +48,15 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 	{{$varNameSingular}}UpdateCacheMut.RUnlock()
 
 	if !cached {
-		wl := strmangle.UpdateColumnSet({{$varNameSingular}}ColumnsWithoutAuto, {{$varNameSingular}}PrimaryKeyColumns, whitelist)
+		wl := strmangle.UpdateColumnSet(
+			{{if ne .DriverName "mssql" -}}
+			{{$varNameSingular}}Columns,
+			{{- else -}}
+			{{$varNameSingular}}ColumnsWithoutAuto,
+			{{- end}}
+			{{$varNameSingular}}PrimaryKeyColumns,
+			whitelist,
+		)
 		{{- if not .NoAutoTimestamps}}
 		if len(whitelist) == 0 {
 			wl = strmangle.SetComplement(wl, []string{"created_at"})
diff --git a/templates_test/update.tpl b/templates_test/update.tpl
index 2612a87..ad98e33 100644
--- a/templates_test/update.tpl
+++ b/templates_test/update.tpl
@@ -79,7 +79,11 @@ func test{{$tableNamePlural}}SliceUpdateAll(t *testing.T) {
 		fields = {{$varNameSingular}}Columns
 	} else {
 		fields = strmangle.SetComplement(
+			{{if ne .DriverName "mssql" -}}
 			{{$varNameSingular}}Columns,
+			{{- else -}}
+			{{$varNameSingular}}ColumnsWithoutAuto,
+			{{- end}}
 			{{$varNameSingular}}PrimaryKeyColumns,
 		)
 	}

From b1b0249898300f4215d90df42ab8a3570da26893 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Thu, 16 Mar 2017 11:01:49 +0300
Subject: [PATCH 083/179] New line at end of file

---
 templates/17_upsert.tpl   | 2 +-
 templates_test/upsert.tpl | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index 5bc9d3e..0aeb479 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -208,4 +208,4 @@ CacheNoHooks:
 	return nil
 	{{- end}}
 }
-{{- end}}
\ No newline at end of file
+{{- end}}
diff --git a/templates_test/upsert.tpl b/templates_test/upsert.tpl
index 68fc435..25807cf 100644
--- a/templates_test/upsert.tpl
+++ b/templates_test/upsert.tpl
@@ -49,4 +49,4 @@ func test{{$tableNamePlural}}Upsert(t *testing.T) {
 		t.Error("want one record, got:", count)
 	}
 }
-{{- end}}
\ No newline at end of file
+{{- end}}

From 2e9535d56e585524669b99bf05e36af453fdd02f Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Thu, 16 Mar 2017 11:29:31 +0300
Subject: [PATCH 084/179] Added uniqueidentifier and xml types (as string)

---
 bdb/drivers/mssql.go | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 254f68d..ec3dc4b 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -313,6 +313,8 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			c.Type = "null.Bytes"
 		case "timestamp", "rowversion":
 			c.Type = "null.Bytes"
+		case "uniqueidentifier", "xml":
+			c.Type = "null.String"
 		default:
 			c.Type = "null.String"
 		}
@@ -340,6 +342,8 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			c.Type = "[]byte"
 		case "timestamp", "rowversion":
 			c.Type = "[]byte"
+		case "uniqueidentifier", "xml":
+			c.Type = "null.String"
 		default:
 			c.Type = "string"
 		}

From 5bc7addb8ac25d720a1fc8a5aca2ca877dea5c63 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Thu, 16 Mar 2017 11:30:07 +0300
Subject: [PATCH 085/179] Randomize for uniqueidentifier data type

---
 randomize/randomize.go | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/randomize/randomize.go b/randomize/randomize.go
index 59f7eff..2af945d 100644
--- a/randomize/randomize.go
+++ b/randomize/randomize.go
@@ -52,7 +52,7 @@ var (
 	rgxValidTime     = regexp.MustCompile(`[2-9]+`)
 
 	validatedTypes = []string{
-		"inet", "line", "uuid", "interval", "mediumint",
+		"inet", "line", "uuid", "uniqueidentifier", "interval", "mediumint",
 		"json", "jsonb", "box", "cidr", "circle",
 		"lseg", "macaddr", "path", "pg_lsn", "point",
 		"polygon", "txid_snapshot", "money", "hstore",
@@ -195,7 +195,7 @@ func randomizeField(s *Seed, field reflect.Value, fieldType string, canBeNull bo
 					field.Set(reflect.ValueOf(value))
 					return nil
 				}
-				if fieldType == "uuid" {
+				if fieldType == "uuid" || fieldType == "uniqueidentifier" {
 					value = null.NewString(uuid.NewV4().String(), true)
 					field.Set(reflect.ValueOf(value))
 					return nil
@@ -268,7 +268,7 @@ func randomizeField(s *Seed, field reflect.Value, fieldType string, canBeNull bo
 					field.Set(reflect.ValueOf(value))
 					return nil
 				}
-				if fieldType == "uuid" {
+				if fieldType == "uuid" || fieldType == "uniqueidentifier" {
 					value = uuid.NewV4().String()
 					field.Set(reflect.ValueOf(value))
 					return nil
@@ -390,7 +390,7 @@ func getArrayRandValue(s *Seed, typ reflect.Type, fieldType string) interface{}
 			value := strconv.Itoa((s.nextInt()%26)+2) + " days"
 			return types.StringArray{value, value}
 		}
-		if fieldType == "uuid" {
+		if fieldType == "uuid" || fieldType == "uniqueidentifier" {
 			value := uuid.NewV4().String()
 			return types.StringArray{value, value}
 		}

From 79f6c344c1e38e53a4fc1fce923dd18f56085ff0 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Thu, 16 Mar 2017 11:30:57 +0300
Subject: [PATCH 086/179] Updates for MS SQL support

---
 README.md | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/README.md b/README.md
index b2d8ae1..00fd5ff 100644
--- a/README.md
+++ b/README.md
@@ -106,9 +106,12 @@ Table of Contents
 
 - PostgreSQL
 - MySQL
+- Microsoft SQL Server
 
 *Note: Seeking contributors for other database engines.*
 
+*Microsoft SQL Server: Limit with offset support only for SQL Server 2012 and above.*
+
 ### A Small Taste
 
 For a comprehensive list of available operations and examples please see [Features & Examples](#features--examples).
@@ -273,6 +276,13 @@ schema="myschema"
   user="dbusername"
   pass="dbpassword"
   sslmode="false"
+[mssql]
+  dbname="dbname"
+  host="localhost"
+  port=1433
+  user="dbusername"
+  pass="dbpassword"
+  sslmode="disable"
 ```
 
 #### Initial Generation
@@ -319,6 +329,9 @@ sqlboiler -b goose_migrations postgres
 go test ./models
 ```
 
+*Note: No `mysqldump` or `pg_dump` equivalent for Microsoft SQL Server, so generated tests must be supplemented by `tables_schema.sql` with `CREATE TABLE ...` queries*
+
+
 You can use `go generate` for SQLBoiler if you want to to make it easy to
 run the command.
 

From 35eefdda41f03ac54d39109109d36b827e662cf1 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Thu, 16 Mar 2017 11:32:24 +0300
Subject: [PATCH 087/179] MS SQL test schema

---
 testdata/mssql_test_schema.sql | 370 +++++++++++++++++++++++++++++++++
 1 file changed, 370 insertions(+)
 create mode 100644 testdata/mssql_test_schema.sql

diff --git a/testdata/mssql_test_schema.sql b/testdata/mssql_test_schema.sql
new file mode 100644
index 0000000..5a529b8
--- /dev/null
+++ b/testdata/mssql_test_schema.sql
@@ -0,0 +1,370 @@
+CREATE TABLE magic
+(
+  id int NOT NULL IDENTITY (1,1) PRIMARY KEY,
+  id_two int NOT NULL,
+  id_three int,
+  bit_zero bit,
+  bit_one bit NULL,
+  bit_two bit NOT NULL,
+  bit_three bit NULL DEFAULT 0,
+  bit_four bit NULL DEFAULT 1,
+  bit_five bit NOT NULL DEFAULT 0,
+  bit_six bit NOT NULL DEFAULT 1,
+  string_zero VARCHAR(1),
+  string_one VARCHAR(1) NULL,
+  string_two VARCHAR(1) NOT NULL,
+  string_three VARCHAR(1) NULL DEFAULT 'a',
+  string_four VARCHAR(1) NOT NULL DEFAULT 'b',
+  string_five VARCHAR(1000),
+  string_six VARCHAR(1000) NULL,
+  string_seven VARCHAR(1000) NOT NULL,
+  string_eight VARCHAR(1000) NULL DEFAULT 'abcdefgh',
+  string_nine VARCHAR(1000) NOT NULL DEFAULT 'abcdefgh',
+  string_ten VARCHAR(1000) NULL DEFAULT '',
+  string_eleven VARCHAR(1000) NOT NULL DEFAULT '',
+  big_int_zero bigint,
+  big_int_one bigint NULL,
+  big_int_two bigint NOT NULL,
+  big_int_three bigint NULL DEFAULT 111111,
+  big_int_four bigint NOT NULL DEFAULT 222222,
+  big_int_five bigint NULL DEFAULT 0,
+  big_int_six bigint NOT NULL DEFAULT 0,
+  int_zero int,
+  int_one int NULL,
+  int_two int NOT NULL,
+  int_three int NULL DEFAULT 333333,
+  int_four int NOT NULL DEFAULT 444444,
+  int_five int NULL DEFAULT 0,
+  int_six int NOT NULL DEFAULT 0,
+  float_zero float,
+  float_one float,
+  float_two float(24),
+  float_three float(24),
+  float_four float(24) NULL,
+  float_five float(24) NOT NULL,
+  float_six float(24) NULL DEFAULT 1.1,
+  float_seven float(24) NOT NULL DEFAULT 1.1,
+  float_eight float(24) NULL DEFAULT 0.0,
+  float_nine float(24) NULL DEFAULT 0.0,
+  bytea_zero binary NOT NULL,
+  bytea_one binary NOT NULL,
+  bytea_two binary NOT NULL,
+  bytea_three binary NOT NULL DEFAULT CONVERT(VARBINARY(MAX),'a'),
+  bytea_four binary NOT NULL DEFAULT CONVERT(VARBINARY(MAX),'b'),
+  bytea_five binary(100) NOT NULL DEFAULT CONVERT(VARBINARY(MAX),'abcdefghabcdefghabcdefgh'),
+  bytea_six binary(100) NOT NULL DEFAULT  CONVERT(VARBINARY(MAX),'hgfedcbahgfedcbahgfedcba'),
+  bytea_seven binary NOT NULL DEFAULT CONVERT(VARBINARY(MAX),''),
+  bytea_eight binary NOT NULL DEFAULT CONVERT(VARBINARY(MAX),''),
+  time_zero timestamp NOT NULL,
+  time_one date,
+  time_eleven date NULL,
+  time_twelve date NOT NULL,
+  time_fifteen date NULL DEFAULT '19990108',
+  time_sixteen date NOT NULL DEFAULT '1999-01-08'
+);
+
+CREATE TABLE magicest
+(
+  id int NOT NULL IDENTITY (1,1) PRIMARY KEY,
+  kk float NULL,
+  ll float NOT NULL,
+  mm tinyint NULL,
+  nn tinyint NOT NULL,
+  oo bit NULL,
+  pp bit NOT NULL,
+  qq smallint NULL,
+  rr smallint NOT NULL,
+  ss int NULL,
+  tt int NOT NULL,
+  uu bigint NULL,
+  vv bigint NOT NULL,
+  ww float NULL,
+  xx float NOT NULL,
+  yy float NULL,
+  zz float NOT NULL,
+  aaa double precision NULL,
+  bbb double precision NOT NULL,
+  ccc real NULL,
+  ddd real NOT NULL,
+  ggg date NULL,
+  hhh date NOT NULL,
+  iii datetime NULL,
+  jjj datetime NOT NULL,
+  kkk timestamp NOT NULL,
+  mmm binary NOT NULL,
+  nnn binary NOT NULL,
+  ooo varbinary(100) NOT NULL,
+  ppp varbinary(100) NOT NULL,
+  qqq varbinary NOT NULL,
+  rrr varbinary NOT NULL,
+  www varbinary(max) NOT NULL,
+  xxx varbinary(max) NOT NULL,
+  yyy varchar(100) NULL,
+  zzz varchar(100) NOT NULL,
+  aaaa char NULL,
+  bbbb char NOT NULL,
+  cccc VARCHAR(MAX) NULL,
+  dddd VARCHAR(MAX) NOT NULL,
+  eeee tinyint NULL,
+  ffff tinyint NOT NULL
+);
+
+create table owner
+(
+  id int NOT NULL IDENTITY (1,1) PRIMARY KEY,
+  name varchar(255) not null
+);
+
+create table cats
+(
+  id int NOT NULL IDENTITY (1,1) PRIMARY KEY,
+  name varchar(255) not null,
+  owner_id int references owner (id)
+);
+
+create table toys
+(
+  id int NOT NULL IDENTITY (1,1) PRIMARY KEY,
+  name varchar(255) not null
+);
+
+create table cat_toys
+(
+  cat_id int not null references cats (id),
+  toy_id int not null references toys (id),
+  primary key (cat_id, toy_id)
+);
+
+create table dog_toys
+(
+  dog_id int not null,
+  toy_id int not null,
+  primary key (dog_id, toy_id)
+);
+
+create table dragon_toys
+(
+  dragon_id varchar(100),
+  toy_id varchar(100),
+  primary key (dragon_id, toy_id)
+);
+
+create table spider_toys
+(
+  spider_id varchar(100) primary key,
+  name varchar(100)
+);
+
+create table pals
+(
+  pal varchar(100) primary key,
+  name varchar(100)
+);
+
+create table friend
+(
+  friend varchar(100) primary key,
+  name varchar(100)
+);
+
+create table bro
+(
+  bros varchar(100) primary key,
+  name varchar(100)
+);
+
+create table enemies
+(
+  enemies varchar(100) primary key,
+  name varchar(100)
+);
+
+create table chocolate
+(
+  dog varchar(100) primary key
+);
+
+create table waffles
+(
+  cat varchar(100) primary key
+);
+
+create table tigers
+(
+  id binary primary key,
+  name binary NOT NULL
+);
+
+create table elephants
+(
+  id binary primary key,
+  name binary not null,
+  tiger_id binary NOT NULL unique,
+  foreign key (tiger_id) references tigers (id)
+);
+
+create table wolves
+(
+  id binary primary key,
+  name binary not null,
+  tiger_id binary not null unique,
+  foreign key (tiger_id) references tigers (id)
+);
+
+create table ants
+(
+  id binary primary key,
+  name binary not null,
+  tiger_id binary not null,
+  foreign key (tiger_id) references tigers (id)
+);
+
+create table worms
+(
+  id binary primary key,
+  name binary not null,
+  tiger_id binary NOT NULL,
+  foreign key (tiger_id) references tigers (id)
+);
+
+create table byte_pilots
+(
+  id binary primary key not null,
+  name varchar(255)
+);
+
+create table byte_airports
+(
+  id binary primary key not null,
+  name varchar(255)
+);
+
+create table byte_languages
+(
+  id binary primary key not null,
+  name varchar(255)
+);
+
+create table byte_jets
+(
+  id binary primary key not null,
+  name varchar(255),
+  byte_pilot_id binary unique NOT NULL,
+  byte_airport_id binary NOT NULL,
+
+  foreign key (byte_pilot_id) references byte_pilots (id),
+  foreign key (byte_airport_id) references byte_airports (id)
+);
+
+create table byte_pilot_languages
+(
+  byte_pilot_id binary not null,
+  byte_language_id binary not null,
+
+  primary key (byte_pilot_id, byte_language_id),
+  foreign key (byte_pilot_id) references byte_pilots (id),
+  foreign key (byte_language_id) references byte_languages (id)
+);
+
+create table cars
+(
+  id integer not null,
+  name VARCHAR(MAX),
+  primary key (id)
+);
+
+create table car_cars
+(
+  car_id integer not null,
+  awesome_car_id integer not null,
+  relation VARCHAR(MAX) not null,
+  primary key (car_id, awesome_car_id),
+  foreign key (car_id) references cars(id),
+  foreign key (awesome_car_id) references cars(id)
+);
+
+create table trucks
+(
+  id integer not null,
+  parent_id integer,
+  name VARCHAR(MAX),
+  primary key (id),
+  foreign key (parent_id) references trucks(id)
+);
+
+CREATE TABLE race
+(
+  id integer PRIMARY KEY NOT NULL,
+  race_date datetime,
+  track VARCHAR(MAX)
+);
+
+CREATE TABLE race_results
+(
+  id integer PRIMARY KEY NOT NULL,
+  race_id integer,
+  name VARCHAR(MAX),
+  foreign key (race_id) references race(id)
+);
+
+CREATE TABLE race_result_scratchings
+(
+  id integer PRIMARY KEY NOT NULL,
+  results_id integer NOT NULL,
+  name VARCHAR(MAX) NOT NULL,
+  foreign key (results_id) references race_results(id)
+);
+
+CREATE TABLE pilots
+(
+  id integer NOT NULL,
+  name VARCHAR(MAX) NOT NULL
+);
+
+ALTER TABLE pilots ADD CONSTRAINT pilot_pkey PRIMARY KEY (id);
+
+CREATE TABLE jets
+(
+  id integer NOT NULL,
+  pilot_id integer NOT NULL,
+  age integer NOT NULL,
+  name VARCHAR(MAX) NOT NULL,
+  color VARCHAR(MAX) NOT NULL
+);
+
+ALTER TABLE jets ADD CONSTRAINT jet_pkey PRIMARY KEY (id);
+ALTER TABLE jets ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
+
+CREATE TABLE languages
+(
+  id integer NOT NULL,
+  language VARCHAR(MAX) NOT NULL
+);
+
+ALTER TABLE languages ADD CONSTRAINT language_pkey PRIMARY KEY (id);
+
+-- Join table
+CREATE TABLE pilot_languages
+(
+  pilot_id integer NOT NULL,
+  language_id integer NOT NULL,
+  uniqueid uniqueidentifier NOT NULL,
+);
+
+-- Composite primary key
+ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pkey PRIMARY KEY (pilot_id, language_id);
+ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
+ALTER TABLE pilot_languages ADD CONSTRAINT languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id);
+
+CREATE TABLE powers_of_two
+(
+  vid int NOT NULL IDENTITY(1,1),
+  name varchar(255) NOT NULL DEFAULT '',
+  machine_name varchar(255) NOT NULL,
+  description VARCHAR(MAX),
+  hierarchy tinyint NOT NULL DEFAULT '0',
+  module varchar(255) NOT NULL DEFAULT '',
+  weight int NOT NULL DEFAULT '0',
+  PRIMARY KEY (vid),
+  CONSTRAINT machine_name UNIQUE(machine_name)
+);

From 4718e72b6df505b6cb1a5655422bce68c367c9dd Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Thu, 16 Mar 2017 11:43:51 +0300
Subject: [PATCH 088/179] Idiomatic quotes

---
 bdb/drivers/mssql.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index ec3dc4b..aaa9ea9 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -354,12 +354,12 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 
 // RightQuote is the quoting character for the right side of the identifier
 func (m *MSSQLDriver) RightQuote() byte {
-	return '"'
+	return ']'
 }
 
 // LeftQuote is the quoting character for the left side of the identifier
 func (m *MSSQLDriver) LeftQuote() byte {
-	return '"'
+	return '['
 }
 
 // IndexPlaceholders returns true to indicate MS SQL supports indexed placeholders

From f3f8074833b085ccefb8a09540285d7d53f63619 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sat, 18 Mar 2017 15:18:04 +0300
Subject: [PATCH 089/179] Removed blank lines and spaces

---
 bdb/drivers/mssql.go                    | 1 -
 strmangle/strmangle.go                  | 6 ------
 templates/15_insert.tpl                 | 2 +-
 templates_test/main_test/mssql_main.tpl | 1 -
 4 files changed, 1 insertion(+), 9 deletions(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index aaa9ea9..7998128 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -32,7 +32,6 @@ func NewMSSQLDriver(user, pass, dbname, host string, port int, sslmode string) *
 
 // MSSQLBuildQueryString builds a query string for MSSQL.
 func MSSQLBuildQueryString(user, pass, dbname, host string, port int, sslmode string) string {
-
 	query := url.Values{}
 	query.Add("database", dbname)
 	query.Add("encrypt", sslmode)
diff --git a/strmangle/strmangle.go b/strmangle/strmangle.go
index b5b68cb..018ffc7 100644
--- a/strmangle/strmangle.go
+++ b/strmangle/strmangle.go
@@ -524,16 +524,11 @@ func WhereClause(lq, rq string, start int, cols []string) string {
 // WhereClauseRepeated returns the where clause repeated with OR clause using start as the $ flag index
 // For example, if start was 2 output would be: "(colthing=$2 AND colstuff=$3) OR (colthing=$4 AND colstuff=$5)"
 func WhereClauseRepeated(lq, rq string, start int, cols []string, count int) string {
-
 	var startIndex int
-
 	buf := GetBuffer()
 	defer PutBuffer(buf)
-
 	buf.WriteByte('(')
-
 	for i := 0; i < count; i++ {
-
 		if i != 0 {
 			buf.WriteString(") OR (")
 		}
@@ -546,7 +541,6 @@ func WhereClauseRepeated(lq, rq string, start int, cols []string, count int) str
 
 		buf.WriteString(WhereClause(lq, rq, startIndex, cols))
 	}
-
 	buf.WriteByte(')')
 
 	return buf.String()
diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index ade915a..1c4be56 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -91,7 +91,7 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 		if len(cache.retMapping) != 0 {
 			{{if .UseLastInsertID -}}
 			cache.retQuery = fmt.Sprintf("SELECT {{.LQ}}%s{{.RQ}} FROM {{$schemaTable}} WHERE %s", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"), strmangle.WhereClause("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns))
-			{{else -}}	
+			{{else -}}
 			cache.query += fmt.Sprintf(" RETURNING {{.LQ}}%s{{.RQ}}", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"))
 			{{- end}}
 		}
diff --git a/templates_test/main_test/mssql_main.tpl b/templates_test/main_test/mssql_main.tpl
index a164819..da96993 100644
--- a/templates_test/main_test/mssql_main.tpl
+++ b/templates_test/main_test/mssql_main.tpl
@@ -34,7 +34,6 @@ func (m *mssqlTester) setup() error {
 	createCmd := exec.Command("sqlcmd", "-S", m.host, "-U", m.user, "-P", m.pass, "-d", m.testDBName)
 
 	f, err := os.Open("tables_schema.sql")
-
 	if err != nil {
 		return errors.Wrap(err, "failed to open tables_schema.sql file")
 	}

From 21917fcfc6481f848b234ffd1a580108e513b3e4 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sat, 18 Mar 2017 15:32:39 +0300
Subject: [PATCH 090/179] Refactored if-else in WhereClauseRepeated

---
 strmangle/strmangle.go | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/strmangle/strmangle.go b/strmangle/strmangle.go
index 018ffc7..b330ac0 100644
--- a/strmangle/strmangle.go
+++ b/strmangle/strmangle.go
@@ -533,10 +533,9 @@ func WhereClauseRepeated(lq, rq string, start int, cols []string, count int) str
 			buf.WriteString(") OR (")
 		}
 
+		startIndex = 0
 		if start > 0 {
 			startIndex = start + i*len(cols)
-		} else {
-			startIndex = 0
 		}
 
 		buf.WriteString(WhereClause(lq, rq, startIndex, cols))

From 8874738f730516bc37dea4928c833b34a3ad0998 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sat, 18 Mar 2017 15:40:17 +0300
Subject: [PATCH 091/179] Fixed query formatting

---
 bdb/drivers/mssql.go | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 7998128..587d761 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -244,18 +244,17 @@ func (m *MSSQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey
 	var fkeys []bdb.ForeignKey
 
 	query := `
-	SELECT 
-		ccu.constraint_name
-		,ccu.table_name AS local_table
-		,ccu.column_name AS local_column
-		,kcu.table_name AS foreign_table
-		,kcu.column_name AS foreign_column
+	SELECT ccu.constraint_name ,
+		ccu.table_name AS local_table ,
+		ccu.column_name AS local_column ,
+		kcu.table_name AS foreign_table ,
+		kcu.column_name AS foreign_column
 	FROM information_schema.constraint_column_usage ccu
-    INNER JOIN information_schema.referential_constraints rc
-        ON ccu.constraint_name = rc.constraint_name 
-    INNER JOIN information_schema.key_column_usage kcu 
-        ON kcu.constraint_name = rc.unique_constraint_name  
-	WHERE ccu.table_schema = ? AND ccu.constraint_schema = ? AND ccu.table_name = ?
+	INNER JOIN information_schema.referential_constraints rc ON ccu.constraint_name = rc.constraint_name
+	INNER JOIN information_schema.key_column_usage kcu ON kcu.constraint_name = rc.unique_constraint_name
+	WHERE ccu.table_schema = ?
+	  AND ccu.constraint_schema = ?
+	  AND ccu.table_name =
 	`
 
 	var rows *sql.Rows

From 7162e9e92754afaa30618586db1143157b8a996e Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sat, 18 Mar 2017 15:47:52 +0300
Subject: [PATCH 092/179] Fixed default port for MS SQL

---
 main.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/main.go b/main.go
index 3f6601e..db9cc07 100644
--- a/main.go
+++ b/main.go
@@ -274,7 +274,7 @@ func preRun(cmd *cobra.Command, args []string) error {
 		}
 
 		if cmdConfig.MSSQL.Port == 0 {
-			cmdConfig.MSSQL.Port = 3306
+			cmdConfig.MSSQL.Port = 1433
 			viper.Set("mssql.port", cmdConfig.MSSQL.Port)
 		}
 

From 97e32c21be0e9e13465d157f4c5540f4a9249c22 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sat, 18 Mar 2017 15:50:03 +0300
Subject: [PATCH 093/179] Default MS SQL sslmode and port for viper

---
 main.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/main.go b/main.go
index db9cc07..a2f9396 100644
--- a/main.go
+++ b/main.go
@@ -95,6 +95,8 @@ func main() {
 	viper.SetDefault("postgres.port", "5432")
 	viper.SetDefault("mysql.sslmode", "true")
 	viper.SetDefault("mysql.port", "3306")
+	viper.SetDefault("mssql.sslmode", "true")
+	viper.SetDefault("mssql.port", "1433")
 
 	viper.BindPFlags(rootCmd.PersistentFlags())
 	viper.AutomaticEnv()

From ccb0c9f6c872341fef8e347b06c7fd7a97a0c501 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sat, 18 Mar 2017 16:22:31 +0300
Subject: [PATCH 094/179] Missed placeholder

---
 bdb/drivers/mssql.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 587d761..380b016 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -254,7 +254,7 @@ func (m *MSSQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey
 	INNER JOIN information_schema.key_column_usage kcu ON kcu.constraint_name = rc.unique_constraint_name
 	WHERE ccu.table_schema = ?
 	  AND ccu.constraint_schema = ?
-	  AND ccu.table_name =
+	  AND ccu.table_name = ?
 	`
 
 	var rows *sql.Rows

From ff5957e4e80b09cd40597fb56fa3eda13fb7322a Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sat, 18 Mar 2017 17:30:35 +0300
Subject: [PATCH 095/179] Fixed queries

---
 testdata/mssql_test_schema.sql | 43 ++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/testdata/mssql_test_schema.sql b/testdata/mssql_test_schema.sql
index 5a529b8..f519680 100644
--- a/testdata/mssql_test_schema.sql
+++ b/testdata/mssql_test_schema.sql
@@ -62,6 +62,7 @@ CREATE TABLE magic
   time_fifteen date NULL DEFAULT '19990108',
   time_sixteen date NOT NULL DEFAULT '1999-01-08'
 );
+GO
 
 CREATE TABLE magicest
 (
@@ -108,12 +109,14 @@ CREATE TABLE magicest
   eeee tinyint NULL,
   ffff tinyint NOT NULL
 );
+GO
 
 create table owner
 (
   id int NOT NULL IDENTITY (1,1) PRIMARY KEY,
   name varchar(255) not null
 );
+GO
 
 create table cats
 (
@@ -121,12 +124,14 @@ create table cats
   name varchar(255) not null,
   owner_id int references owner (id)
 );
+GO
 
 create table toys
 (
   id int NOT NULL IDENTITY (1,1) PRIMARY KEY,
   name varchar(255) not null
 );
+GO
 
 create table cat_toys
 (
@@ -134,6 +139,7 @@ create table cat_toys
   toy_id int not null references toys (id),
   primary key (cat_id, toy_id)
 );
+GO
 
 create table dog_toys
 (
@@ -141,6 +147,7 @@ create table dog_toys
   toy_id int not null,
   primary key (dog_id, toy_id)
 );
+GO
 
 create table dragon_toys
 (
@@ -148,52 +155,61 @@ create table dragon_toys
   toy_id varchar(100),
   primary key (dragon_id, toy_id)
 );
+GO
 
 create table spider_toys
 (
   spider_id varchar(100) primary key,
   name varchar(100)
 );
+GO
 
 create table pals
 (
   pal varchar(100) primary key,
   name varchar(100)
 );
+GO
 
 create table friend
 (
   friend varchar(100) primary key,
   name varchar(100)
 );
+GO
 
 create table bro
 (
   bros varchar(100) primary key,
   name varchar(100)
 );
+GO
 
 create table enemies
 (
   enemies varchar(100) primary key,
   name varchar(100)
 );
+GO
 
 create table chocolate
 (
   dog varchar(100) primary key
 );
+GO
 
 create table waffles
 (
   cat varchar(100) primary key
 );
+GO
 
 create table tigers
 (
   id binary primary key,
   name binary NOT NULL
 );
+GO
 
 create table elephants
 (
@@ -202,6 +218,7 @@ create table elephants
   tiger_id binary NOT NULL unique,
   foreign key (tiger_id) references tigers (id)
 );
+GO
 
 create table wolves
 (
@@ -210,6 +227,7 @@ create table wolves
   tiger_id binary not null unique,
   foreign key (tiger_id) references tigers (id)
 );
+GO
 
 create table ants
 (
@@ -218,6 +236,7 @@ create table ants
   tiger_id binary not null,
   foreign key (tiger_id) references tigers (id)
 );
+GO
 
 create table worms
 (
@@ -226,24 +245,28 @@ create table worms
   tiger_id binary NOT NULL,
   foreign key (tiger_id) references tigers (id)
 );
+GO
 
 create table byte_pilots
 (
   id binary primary key not null,
   name varchar(255)
 );
+GO
 
 create table byte_airports
 (
   id binary primary key not null,
   name varchar(255)
 );
+GO
 
 create table byte_languages
 (
   id binary primary key not null,
   name varchar(255)
 );
+GO
 
 create table byte_jets
 (
@@ -255,6 +278,7 @@ create table byte_jets
   foreign key (byte_pilot_id) references byte_pilots (id),
   foreign key (byte_airport_id) references byte_airports (id)
 );
+GO
 
 create table byte_pilot_languages
 (
@@ -265,6 +289,7 @@ create table byte_pilot_languages
   foreign key (byte_pilot_id) references byte_pilots (id),
   foreign key (byte_language_id) references byte_languages (id)
 );
+GO
 
 create table cars
 (
@@ -272,6 +297,7 @@ create table cars
   name VARCHAR(MAX),
   primary key (id)
 );
+GO
 
 create table car_cars
 (
@@ -282,6 +308,7 @@ create table car_cars
   foreign key (car_id) references cars(id),
   foreign key (awesome_car_id) references cars(id)
 );
+GO
 
 create table trucks
 (
@@ -291,6 +318,7 @@ create table trucks
   primary key (id),
   foreign key (parent_id) references trucks(id)
 );
+GO
 
 CREATE TABLE race
 (
@@ -298,6 +326,7 @@ CREATE TABLE race
   race_date datetime,
   track VARCHAR(MAX)
 );
+GO
 
 CREATE TABLE race_results
 (
@@ -306,6 +335,7 @@ CREATE TABLE race_results
   name VARCHAR(MAX),
   foreign key (race_id) references race(id)
 );
+GO
 
 CREATE TABLE race_result_scratchings
 (
@@ -314,14 +344,17 @@ CREATE TABLE race_result_scratchings
   name VARCHAR(MAX) NOT NULL,
   foreign key (results_id) references race_results(id)
 );
+GO
 
 CREATE TABLE pilots
 (
   id integer NOT NULL,
   name VARCHAR(MAX) NOT NULL
 );
+GO
 
 ALTER TABLE pilots ADD CONSTRAINT pilot_pkey PRIMARY KEY (id);
+GO
 
 CREATE TABLE jets
 (
@@ -331,17 +364,22 @@ CREATE TABLE jets
   name VARCHAR(MAX) NOT NULL,
   color VARCHAR(MAX) NOT NULL
 );
+GO
 
 ALTER TABLE jets ADD CONSTRAINT jet_pkey PRIMARY KEY (id);
+GO
 ALTER TABLE jets ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
+GO
 
 CREATE TABLE languages
 (
   id integer NOT NULL,
   language VARCHAR(MAX) NOT NULL
 );
+GO
 
 ALTER TABLE languages ADD CONSTRAINT language_pkey PRIMARY KEY (id);
+GO
 
 -- Join table
 CREATE TABLE pilot_languages
@@ -350,11 +388,15 @@ CREATE TABLE pilot_languages
   language_id integer NOT NULL,
   uniqueid uniqueidentifier NOT NULL,
 );
+GO
 
 -- Composite primary key
 ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pkey PRIMARY KEY (pilot_id, language_id);
+GO
 ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
+GO
 ALTER TABLE pilot_languages ADD CONSTRAINT languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id);
+GO
 
 CREATE TABLE powers_of_two
 (
@@ -368,3 +410,4 @@ CREATE TABLE powers_of_two
   PRIMARY KEY (vid),
   CONSTRAINT machine_name UNIQUE(machine_name)
 );
+GO

From e6c6056353beb19753e445418bbc4d67ff16f728 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sun, 19 Mar 2017 00:02:14 +0300
Subject: [PATCH 096/179] Fixed CREATE DATABASE query

---
 templates_test/main_test/mssql_main.tpl | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/templates_test/main_test/mssql_main.tpl b/templates_test/main_test/mssql_main.tpl
index da96993..c1c76f2 100644
--- a/templates_test/main_test/mssql_main.tpl
+++ b/templates_test/main_test/mssql_main.tpl
@@ -66,7 +66,9 @@ func (m *mssqlTester) sslMode(mode string) string {
 }
 
 func (m *mssqlTester) createTestDB() error {
-	sql := fmt.Sprintf("create database %s;", m.testDBName)
+	sql := fmt.Sprintf(`
+	CREATE DATABASE %s;
+	GO`, m.testDBName)
 	return m.runCmd(sql, "sqlcmd", "-S", m.host, "-U", m.user, "-P", m.pass)
 }
 

From 49d052af53f1497f18dee5ba7a26a1aea3866a09 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sun, 19 Mar 2017 12:34:19 +0300
Subject: [PATCH 097/179] FKs moved to alter caluse

---
 testdata/mssql_test_schema.sql | 80 ++++++++++++++++++++++------------
 1 file changed, 53 insertions(+), 27 deletions(-)

diff --git a/testdata/mssql_test_schema.sql b/testdata/mssql_test_schema.sql
index f519680..94ff5dc 100644
--- a/testdata/mssql_test_schema.sql
+++ b/testdata/mssql_test_schema.sql
@@ -122,10 +122,13 @@ create table cats
 (
   id int NOT NULL IDENTITY (1,1) PRIMARY KEY,
   name varchar(255) not null,
-  owner_id int references owner (id)
+  owner_id int
 );
 GO
 
+ALTER TABLE cats ADD CONSTRAINT cats_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES owner(id);
+GO
+
 create table toys
 (
   id int NOT NULL IDENTITY (1,1) PRIMARY KEY,
@@ -215,38 +218,46 @@ create table elephants
 (
   id binary primary key,
   name binary not null,
-  tiger_id binary NOT NULL unique,
-  foreign key (tiger_id) references tigers (id)
+  tiger_id binary NOT NULL unique
 );
 GO
 
+ALTER TABLE elephants ADD CONSTRAINT elephants_tiger_id_fkey FOREIGN KEY (tiger_id) REFERENCES tigers(id);
+GO
+
 create table wolves
 (
   id binary primary key,
   name binary not null,
-  tiger_id binary not null unique,
-  foreign key (tiger_id) references tigers (id)
+  tiger_id binary not null unique
 );
 GO
 
+ALTER TABLE wolves ADD CONSTRAINT wolves_tiger_id_fkey FOREIGN KEY (tiger_id) REFERENCES tigers(id);
+GO
+
 create table ants
 (
   id binary primary key,
   name binary not null,
-  tiger_id binary not null,
-  foreign key (tiger_id) references tigers (id)
+  tiger_id binary not null
 );
 GO
 
+ALTER TABLE ants ADD CONSTRAINT ants_tiger_id_fkey FOREIGN KEY (tiger_id) REFERENCES tigers(id);
+GO
+
 create table worms
 (
   id binary primary key,
   name binary not null,
-  tiger_id binary NOT NULL,
-  foreign key (tiger_id) references tigers (id)
+  tiger_id binary NOT NULL
 );
 GO
 
+ALTER TABLE worms ADD CONSTRAINT worms_tiger_id_fkey FOREIGN KEY (tiger_id) REFERENCES tigers(id);
+GO
+
 create table byte_pilots
 (
   id binary primary key not null,
@@ -273,24 +284,30 @@ create table byte_jets
   id binary primary key not null,
   name varchar(255),
   byte_pilot_id binary unique NOT NULL,
-  byte_airport_id binary NOT NULL,
-
-  foreign key (byte_pilot_id) references byte_pilots (id),
-  foreign key (byte_airport_id) references byte_airports (id)
+  byte_airport_id binary NOT NULL
 );
 GO
 
+ALTER TABLE byte_jets ADD CONSTRAINT byte_pilot_id_fkey FOREIGN KEY (byte_pilot_id) REFERENCES byte_pilots(id);
+GO
+ALTER TABLE byte_jets ADD CONSTRAINT byte_airport_id_fkey FOREIGN KEY (byte_airport_id) REFERENCES byte_airports(id);
+GO
+
 create table byte_pilot_languages
 (
   byte_pilot_id binary not null,
-  byte_language_id binary not null,
-
-  primary key (byte_pilot_id, byte_language_id),
-  foreign key (byte_pilot_id) references byte_pilots (id),
-  foreign key (byte_language_id) references byte_languages (id)
+  byte_language_id binary not null
 );
 GO
 
+ALTER TABLE byte_pilot_languages ADD CONSTRAINT byte_pilot_languages_pkey PRIMARY KEY (byte_pilot_id,byte_language_id);
+GO
+
+ALTER TABLE byte_pilot_languages ADD CONSTRAINT byte_pilot_id_fkey FOREIGN KEY (byte_pilot_id) REFERENCES byte_pilots(id);
+GO
+ALTER TABLE byte_pilot_languages ADD CONSTRAINT byte_language_id_fkey FOREIGN KEY (byte_language_id) REFERENCES byte_languages(id);
+GO
+
 create table cars
 (
   id integer not null,
@@ -304,22 +321,27 @@ create table car_cars
   car_id integer not null,
   awesome_car_id integer not null,
   relation VARCHAR(MAX) not null,
-  primary key (car_id, awesome_car_id),
-  foreign key (car_id) references cars(id),
-  foreign key (awesome_car_id) references cars(id)
+  primary key (car_id, awesome_car_id)
 );
 GO
 
+ALTER TABLE car_cars ADD CONSTRAINT car_id_fkey FOREIGN KEY (car_id) REFERENCES cars(id);
+GO
+ALTER TABLE car_cars ADD CONSTRAINT awesome_car_id_fkey FOREIGN KEY (awesome_car_id) REFERENCES cars(id);
+GO
+
 create table trucks
 (
   id integer not null,
   parent_id integer,
   name VARCHAR(MAX),
-  primary key (id),
-  foreign key (parent_id) references trucks(id)
+  primary key (id)
 );
 GO
 
+ALTER TABLE trucks ADD CONSTRAINT parent_id_fkey FOREIGN KEY (parent_id) REFERENCES trucks(id);
+GO
+
 CREATE TABLE race
 (
   id integer PRIMARY KEY NOT NULL,
@@ -332,20 +354,24 @@ CREATE TABLE race_results
 (
   id integer PRIMARY KEY NOT NULL,
   race_id integer,
-  name VARCHAR(MAX),
-  foreign key (race_id) references race(id)
+  name VARCHAR(MAX)
 );
 GO
 
+ALTER TABLE race_results ADD CONSTRAINT race_id_fkey FOREIGN KEY (race_id) REFERENCES race(id);
+GO
+
 CREATE TABLE race_result_scratchings
 (
   id integer PRIMARY KEY NOT NULL,
   results_id integer NOT NULL,
-  name VARCHAR(MAX) NOT NULL,
-  foreign key (results_id) references race_results(id)
+  name VARCHAR(MAX) NOT NULL
 );
 GO
 
+ALTER TABLE race_result_scratchings ADD CONSTRAINT results_id_fkey FOREIGN KEY (results_id) REFERENCES race_results(id);
+GO
+
 CREATE TABLE pilots
 (
   id integer NOT NULL,

From a508530f6304d60ba5b49f79dda230fcdfed94a5 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sun, 19 Mar 2017 12:39:59 +0300
Subject: [PATCH 098/179] Allow UseLastInsertID

---
 bdb/drivers/mssql.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 380b016..a3a6a34 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -65,7 +65,7 @@ func (m *MSSQLDriver) Close() {
 
 // UseLastInsertID returns false for mssql
 func (m *MSSQLDriver) UseLastInsertID() bool {
-	return false
+	return true
 }
 
 // UseTopClause returns true to indicate MS SQL supports SQL TOP clause

From 12dce9d9868f1b1114349e230deafe5355176430 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sun, 19 Mar 2017 12:42:55 +0300
Subject: [PATCH 099/179] Auto columns in Inserts removed

---
 bdb/column.go           | 2 +-
 bdb/drivers/mssql.go    | 4 +++-
 templates/01_types.tpl  | 2 +-
 templates/15_insert.tpl | 6 ------
 4 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/bdb/column.go b/bdb/column.go
index d33e0cb..a3632fc 100644
--- a/bdb/column.go
+++ b/bdb/column.go
@@ -75,7 +75,7 @@ func FilterColumnsByDefault(defaults bool, columns []Column) []Column {
 	var cols []Column
 
 	for _, c := range columns {
-		if (defaults && (len(c.Default) != 0 || c.AutoGenerated)) || (!defaults && len(c.Default) == 0 && !c.AutoGenerated) {
+		if (defaults && len(c.Default) != 0) || (!defaults && len(c.Default) == 0) {
 			cols = append(cols, c)
 		}
 	}
diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index a3a6a34..6ffee08 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -169,7 +169,7 @@ func (m *MSSQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
 			return nil, errors.Wrapf(err, "unable to scan for table %s", tableName)
 		}
 
-		auto = identity || strings.EqualFold(colType, "timestamp") || strings.EqualFold(colType, "rowversion")
+		auto = strings.EqualFold(colType, "timestamp") || strings.EqualFold(colType, "rowversion")
 
 		column := bdb.Column{
 			Name:          colName,
@@ -182,6 +182,8 @@ func (m *MSSQLDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
 
 		if defaultValue != nil && *defaultValue != "NULL" {
 			column.Default = *defaultValue
+		} else if identity || auto {
+			column.Default = "auto"
 		}
 		columns = append(columns, column)
 	}
diff --git a/templates/01_types.tpl b/templates/01_types.tpl
index 32a5d41..bcf0a94 100644
--- a/templates/01_types.tpl
+++ b/templates/01_types.tpl
@@ -5,7 +5,7 @@
 var (
 	{{$varNameSingular}}Columns               = []string{{"{"}}{{.Table.Columns | columnNames | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}}
 	{{if eq .DriverName "mssql" -}}
-	{{$varNameSingular}}ColumnsWithoutAuto = []string{{"{"}}{{.Table.Columns | filterColumnsByAuto false | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
+	{{$varNameSingular}}ColumnsWithAuto = []string{{"{"}}{{.Table.Columns | filterColumnsByAuto true | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
 	{{- end}}
 	{{$varNameSingular}}ColumnsWithoutDefault = []string{{"{"}}{{.Table.Columns | filterColumnsByDefault false | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
 	{{$varNameSingular}}ColumnsWithDefault    = []string{{"{"}}{{.Table.Columns | filterColumnsByDefault true | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index 1c4be56..3b66281 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -50,11 +50,7 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 
 	if !cached {
 		wl, returnColumns := strmangle.InsertColumnSet(
-			{{if ne .DriverName "mssql" -}}
 			{{$varNameSingular}}Columns,
-			{{- else -}}
-			{{$varNameSingular}}ColumnsWithoutAuto,
-			{{- end}}
 			{{$varNameSingular}}ColumnsWithDefault,
 			{{$varNameSingular}}ColumnsWithoutDefault,
 			nzDefaults,
@@ -87,7 +83,6 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 			{{end -}}
 		}
 
-		{{if ne .DriverName "mssql" -}}
 		if len(cache.retMapping) != 0 {
 			{{if .UseLastInsertID -}}
 			cache.retQuery = fmt.Sprintf("SELECT {{.LQ}}%s{{.RQ}} FROM {{$schemaTable}} WHERE %s", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"), strmangle.WhereClause("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns))
@@ -95,7 +90,6 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 			cache.query += fmt.Sprintf(" RETURNING {{.LQ}}%s{{.RQ}}", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"))
 			{{- end}}
 		}
-		{{end -}}
 	}
 
 	value := reflect.Indirect(reflect.ValueOf(o))

From d40d074320d11b1f133b393eeb78104d79298ca0 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sun, 19 Mar 2017 12:44:15 +0300
Subject: [PATCH 100/179] Filtering columns with auto values

---
 templates/16_update.tpl   |  7 +++----
 templates_test/update.tpl | 10 ++++++----
 2 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index f9eef64..2ee87cc 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -49,14 +49,13 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 
 	if !cached {
 		wl := strmangle.UpdateColumnSet(
-			{{if ne .DriverName "mssql" -}}
 			{{$varNameSingular}}Columns,
-			{{- else -}}
-			{{$varNameSingular}}ColumnsWithoutAuto,
-			{{- end}}
 			{{$varNameSingular}}PrimaryKeyColumns,
 			whitelist,
 		)
+		{{if eq .DriverName "mssql"}}
+		wl = strmangle.SetComplement(wl, {{$varNameSingular}}ColumnsWithAuto)
+		{{end}}
 		{{- if not .NoAutoTimestamps}}
 		if len(whitelist) == 0 {
 			wl = strmangle.SetComplement(wl, []string{"created_at"})
diff --git a/templates_test/update.tpl b/templates_test/update.tpl
index ad98e33..d04401a 100644
--- a/templates_test/update.tpl
+++ b/templates_test/update.tpl
@@ -79,13 +79,15 @@ func test{{$tableNamePlural}}SliceUpdateAll(t *testing.T) {
 		fields = {{$varNameSingular}}Columns
 	} else {
 		fields = strmangle.SetComplement(
-			{{if ne .DriverName "mssql" -}}
 			{{$varNameSingular}}Columns,
-			{{- else -}}
-			{{$varNameSingular}}ColumnsWithoutAuto,
-			{{- end}}
 			{{$varNameSingular}}PrimaryKeyColumns,
 		)
+		{{- if eq .DriverName "mssql"}}
+		fields = strmangle.SetComplement(
+			fields,
+			{{$varNameSingular}}ColumnsWithAuto,
+		)
+		{{- end}}
 	}
 
 	value := reflect.Indirect(reflect.ValueOf({{$varNameSingular}}))

From 68ac8a3c344a7062828dfd8331066d1c61b9e8e9 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sun, 19 Mar 2017 18:05:55 +0300
Subject: [PATCH 101/179] Disabled UseLastInsertID in favor of query output
 params

---
 bdb/drivers/mssql.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 6ffee08..9d20d0f 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -65,7 +65,7 @@ func (m *MSSQLDriver) Close() {
 
 // UseLastInsertID returns false for mssql
 func (m *MSSQLDriver) UseLastInsertID() bool {
-	return true
+	return false
 }
 
 // UseTopClause returns true to indicate MS SQL supports SQL TOP clause

From 13bdda4e20f3791984406e247e8d38b476b55788 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sun, 19 Mar 2017 18:12:06 +0300
Subject: [PATCH 102/179] Simplified insert query

---
 templates/15_insert.tpl | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index 3b66281..bb72404 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -66,15 +66,7 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 			return err
 		}
 		if len(wl) != 0 {
-			{{if ne .DriverName "mssql" -}}
-			cache.query = fmt.Sprintf("INSERT INTO {{$schemaTable}} ({{.LQ}}%s{{.RQ}}) VALUES (%s)", strings.Join(wl, "{{.RQ}},{{.LQ}}"), strmangle.Placeholders(dialect.IndexPlaceholders, len(wl), 1, 1))
-			{{- else -}}
-			if len(cache.retMapping) == 0 {
-				cache.query = fmt.Sprintf("INSERT INTO {{$schemaTable}} ({{.LQ}}%s{{.RQ}}) VALUES (%s)", strings.Join(wl, "{{.RQ}},{{.LQ}}"), strmangle.Placeholders(dialect.IndexPlaceholders, len(wl), 1, 1))			
-			} else {
-				cache.query = fmt.Sprintf("INSERT INTO {{$schemaTable}} ({{.LQ}}%s{{.RQ}}) OUTPUT INSERTED.{{.LQ}}%s{{.RQ}} VALUES (%s)", strings.Join(wl, "{{.RQ}},{{.LQ}}"), strings.Join(returnColumns, "{{.RQ}},INSERTED.{{.LQ}}"), strmangle.Placeholders(dialect.IndexPlaceholders, len(wl), 1, 1))			
-			}
-			{{- end}}
+			cache.query = fmt.Sprintf("INSERT INTO {{$schemaTable}} ({{.LQ}}%s{{.RQ}}) %%sVALUES (%s)%%s", strings.Join(wl, "{{.RQ}},{{.LQ}}"), strmangle.Placeholders(dialect.IndexPlaceholders, len(wl), 1, 1))
 		} else {
 			{{if eq .DriverName "mysql" -}}
 			cache.query = "INSERT INTO {{$schemaTable}} () VALUES ()"
@@ -83,13 +75,21 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 			{{end -}}
 		}
 
+		queryOutput := ""
+		qyeryReturning := ""
+
 		if len(cache.retMapping) != 0 {
 			{{if .UseLastInsertID -}}
 			cache.retQuery = fmt.Sprintf("SELECT {{.LQ}}%s{{.RQ}} FROM {{$schemaTable}} WHERE %s", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"), strmangle.WhereClause("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns))
 			{{else -}}
-			cache.query += fmt.Sprintf(" RETURNING {{.LQ}}%s{{.RQ}}", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"))
+				{{if ne .DriverName "mssql" -}}
+			qyeryReturning = fmt.Sprintf(" RETURNING {{.LQ}}%s{{.RQ}}", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"))
+				{{else -}}
+			queryOutput = fmt.Sprintf("OUTPUT INSERTED.{{.LQ}}%s{{.RQ}} ", strings.Join(returnColumns, "{{.RQ}},INSERTED.{{.LQ}}"))
+				{{end -}}
 			{{- end}}
 		}
+		cache.query = fmt.Sprintf(cache.query, queryOutput, qyeryReturning)
 	}
 
 	value := reflect.Indirect(reflect.ValueOf(o))

From 6bc6b1690cead722833e80b5c7a24b4f6f4323dc Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Mon, 20 Mar 2017 12:50:33 +0300
Subject: [PATCH 103/179] Fixed FK constraints

---
 testdata/mssql_test_schema.sql | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/testdata/mssql_test_schema.sql b/testdata/mssql_test_schema.sql
index 94ff5dc..0995aa1 100644
--- a/testdata/mssql_test_schema.sql
+++ b/testdata/mssql_test_schema.sql
@@ -288,9 +288,9 @@ create table byte_jets
 );
 GO
 
-ALTER TABLE byte_jets ADD CONSTRAINT byte_pilot_id_fkey FOREIGN KEY (byte_pilot_id) REFERENCES byte_pilots(id);
+ALTER TABLE byte_jets ADD CONSTRAINT byte_jets_byte_pilot_id_fkey FOREIGN KEY (byte_pilot_id) REFERENCES byte_pilots(id);
 GO
-ALTER TABLE byte_jets ADD CONSTRAINT byte_airport_id_fkey FOREIGN KEY (byte_airport_id) REFERENCES byte_airports(id);
+ALTER TABLE byte_jets ADD CONSTRAINT byte_jets_byte_airport_id_fkey FOREIGN KEY (byte_airport_id) REFERENCES byte_airports(id);
 GO
 
 create table byte_pilot_languages
@@ -303,9 +303,9 @@ GO
 ALTER TABLE byte_pilot_languages ADD CONSTRAINT byte_pilot_languages_pkey PRIMARY KEY (byte_pilot_id,byte_language_id);
 GO
 
-ALTER TABLE byte_pilot_languages ADD CONSTRAINT byte_pilot_id_fkey FOREIGN KEY (byte_pilot_id) REFERENCES byte_pilots(id);
+ALTER TABLE byte_pilot_languages ADD CONSTRAINT byte_pilot_languages_byte_pilot_id_fkey FOREIGN KEY (byte_pilot_id) REFERENCES byte_pilots(id);
 GO
-ALTER TABLE byte_pilot_languages ADD CONSTRAINT byte_language_id_fkey FOREIGN KEY (byte_language_id) REFERENCES byte_languages(id);
+ALTER TABLE byte_pilot_languages ADD CONSTRAINT byte_pilot_languages_byte_language_id_fkey FOREIGN KEY (byte_language_id) REFERENCES byte_languages(id);
 GO
 
 create table cars

From 9bafa2f1586c2fe51671fea6831958e5875b26c8 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 21 Mar 2017 13:04:07 +0300
Subject: [PATCH 104/179] MSSQL Upsert statement

---
 queries/query_builders.go                     | 43 +++++++++++++
 templates/01_types.tpl                        |  2 -
 templates/02_hooks.tpl                        | 12 ----
 templates/17_upsert.tpl                       | 60 +++++++++++++------
 templates_test/hooks.tpl                      |  4 --
 templates_test/singleton/boil_suites_test.tpl |  5 +-
 templates_test/upsert.tpl                     |  4 +-
 7 files changed, 89 insertions(+), 41 deletions(-)

diff --git a/queries/query_builders.go b/queries/query_builders.go
index 3136693..7cf753f 100644
--- a/queries/query_builders.go
+++ b/queries/query_builders.go
@@ -283,6 +283,49 @@ func BuildUpsertQueryPostgres(dia Dialect, tableName string, updateOnConflict bo
 	return buf.String()
 }
 
+// BuildUpsertQueryMSSQL builds a SQL statement string using the upsertData provided.
+func BuildUpsertQueryMSSQL(dia Dialect, tableName string, primary, update, insert []string, output []string) string {
+	insert = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, insert)
+
+	buf := strmangle.GetBuffer()
+	defer strmangle.PutBuffer(buf)
+
+	startIndex := 1
+
+	fmt.Fprintf(buf, "MERGE INTO %s as [t]\n", tableName)
+	fmt.Fprintf(buf, "USING (SELECT %s) as [s] ([%s])\n",
+		strmangle.Placeholders(dia.IndexPlaceholders, len(primary), startIndex, 1),
+		strings.Join(primary, string(dia.RQ)+","+string(dia.LQ)))
+	fmt.Fprint(buf, "ON (")
+	for i, v := range primary {
+		if i != 0 {
+			fmt.Fprint(buf, " AND ")
+		}
+		fmt.Fprintf(buf, "[s].[%s] = [t].[%s]", v, v)
+	}
+	fmt.Fprint(buf, ")\n")
+
+	startIndex = len(primary) + 1
+
+	fmt.Fprint(buf, "WHEN MATCHED THEN ")
+	fmt.Fprintf(buf, "UPDATE SET %s\n", strmangle.SetParamNames(string(dia.LQ), string(dia.RQ), startIndex, update))
+
+	startIndex = len(primary) + 1 + len(update)
+
+	fmt.Fprint(buf, "WHEN NOT MATCHED THEN ")
+	fmt.Fprintf(buf, "INSERT (%s) VALUES (%s)",
+		strings.Join(insert, ", "),
+		strmangle.Placeholders(dia.IndexPlaceholders, len(insert), startIndex, 1))
+
+	if len(output) > 0 {
+		fmt.Fprintf(buf, "\nOUTPUT INSERTED.[%s];", strings.Join(output, "],INSERTED.["))
+	} else {
+		fmt.Fprint(buf, ";")
+	}
+
+	return buf.String()
+}
+
 func writeModifiers(q *Query, buf *bytes.Buffer, args *[]interface{}) {
 	if len(q.groupBy) != 0 {
 		fmt.Fprintf(buf, " GROUP BY %s", strings.Join(q.groupBy, ", "))
diff --git a/templates/01_types.tpl b/templates/01_types.tpl
index bcf0a94..1f8d015 100644
--- a/templates/01_types.tpl
+++ b/templates/01_types.tpl
@@ -35,10 +35,8 @@ var (
 	{{$varNameSingular}}InsertCache = make(map[string]insertCache)
 	{{$varNameSingular}}UpdateCacheMut sync.RWMutex
 	{{$varNameSingular}}UpdateCache = make(map[string]updateCache)
-	{{if ne .DriverName "mssql"}}
 	{{$varNameSingular}}UpsertCacheMut sync.RWMutex
 	{{$varNameSingular}}UpsertCache = make(map[string]insertCache)
-	{{end}}
 )
 
 var (
diff --git a/templates/02_hooks.tpl b/templates/02_hooks.tpl
index 073f8ec..9815639 100644
--- a/templates/02_hooks.tpl
+++ b/templates/02_hooks.tpl
@@ -4,17 +4,13 @@
 var {{$varNameSingular}}BeforeInsertHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}BeforeUpdateHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}BeforeDeleteHooks []{{$tableNameSingular}}Hook
-{{if ne .DriverName "mssql" -}}
 var {{$varNameSingular}}BeforeUpsertHooks []{{$tableNameSingular}}Hook
-{{- end}}
 
 var {{$varNameSingular}}AfterInsertHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}AfterSelectHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}AfterUpdateHooks []{{$tableNameSingular}}Hook
 var {{$varNameSingular}}AfterDeleteHooks []{{$tableNameSingular}}Hook
-{{if ne .DriverName "mssql" -}}
 var {{$varNameSingular}}AfterUpsertHooks []{{$tableNameSingular}}Hook
-{{- end}}
 
 // doBeforeInsertHooks executes all "before insert" hooks.
 func (o *{{$tableNameSingular}}) doBeforeInsertHooks(exec boil.Executor) (err error) {
@@ -49,7 +45,6 @@ func (o *{{$tableNameSingular}}) doBeforeDeleteHooks(exec boil.Executor) (err er
 	return nil
 }
 
-{{- if ne .DriverName "mssql" -}}
 // doBeforeUpsertHooks executes all "before Upsert" hooks.
 func (o *{{$tableNameSingular}}) doBeforeUpsertHooks(exec boil.Executor) (err error) {
 	for _, hook := range {{$varNameSingular}}BeforeUpsertHooks {
@@ -60,7 +55,6 @@ func (o *{{$tableNameSingular}}) doBeforeUpsertHooks(exec boil.Executor) (err er
 
 	return nil
 }
-{{- end}}
 
 // doAfterInsertHooks executes all "after Insert" hooks.
 func (o *{{$tableNameSingular}}) doAfterInsertHooks(exec boil.Executor) (err error) {
@@ -106,7 +100,6 @@ func (o *{{$tableNameSingular}}) doAfterDeleteHooks(exec boil.Executor) (err err
 	return nil
 }
 
-{{- if ne .DriverName "mssql" -}}
 // doAfterUpsertHooks executes all "after Upsert" hooks.
 func (o *{{$tableNameSingular}}) doAfterUpsertHooks(exec boil.Executor) (err error) {
 	for _, hook := range {{$varNameSingular}}AfterUpsertHooks {
@@ -117,7 +110,6 @@ func (o *{{$tableNameSingular}}) doAfterUpsertHooks(exec boil.Executor) (err err
 
 	return nil
 }
-{{- end}}
 
 // Add{{$tableNameSingular}}Hook registers your hook function for all future operations.
 func Add{{$tableNameSingular}}Hook(hookPoint boil.HookPoint, {{$varNameSingular}}Hook {{$tableNameSingular}}Hook) {
@@ -128,10 +120,8 @@ func Add{{$tableNameSingular}}Hook(hookPoint boil.HookPoint, {{$varNameSingular}
 			{{$varNameSingular}}BeforeUpdateHooks = append({{$varNameSingular}}BeforeUpdateHooks, {{$varNameSingular}}Hook)
 		case boil.BeforeDeleteHook:
 			{{$varNameSingular}}BeforeDeleteHooks = append({{$varNameSingular}}BeforeDeleteHooks, {{$varNameSingular}}Hook)
-		{{if ne .DriverName "mssql" -}}
 		case boil.BeforeUpsertHook:
 			{{$varNameSingular}}BeforeUpsertHooks = append({{$varNameSingular}}BeforeUpsertHooks, {{$varNameSingular}}Hook)
-		{{- end}}
 		case boil.AfterInsertHook:
 			{{$varNameSingular}}AfterInsertHooks = append({{$varNameSingular}}AfterInsertHooks, {{$varNameSingular}}Hook)
 		case boil.AfterSelectHook:
@@ -140,10 +130,8 @@ func Add{{$tableNameSingular}}Hook(hookPoint boil.HookPoint, {{$varNameSingular}
 			{{$varNameSingular}}AfterUpdateHooks = append({{$varNameSingular}}AfterUpdateHooks, {{$varNameSingular}}Hook)
 		case boil.AfterDeleteHook:
 			{{$varNameSingular}}AfterDeleteHooks = append({{$varNameSingular}}AfterDeleteHooks, {{$varNameSingular}}Hook)
-		{{if ne .DriverName "mssql" -}}
 		case boil.AfterUpsertHook:
 			{{$varNameSingular}}AfterUpsertHooks = append({{$varNameSingular}}AfterUpsertHooks, {{$varNameSingular}}Hook)
-		{{- end}}
 	}
 }
 {{- end}}
diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index 0aeb479..70df4c7 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -1,29 +1,28 @@
-{{- if ne .DriverName "mssql" -}}
 {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
 {{- $varNameSingular := .Table.Name | singular | camelCase -}}
 {{- $schemaTable := .Table.Name | .SchemaTable}}
 // UpsertG attempts an insert, and does an update or ignore on conflict.
-func (o *{{$tableNameSingular}}) UpsertG({{if ne .DriverName "mysql"}}updateOnConflict bool, conflictColumns []string, {{end}}updateColumns []string,	whitelist ...string) error {
-	return o.Upsert(boil.GetDB(), {{if ne .DriverName "mysql"}}updateOnConflict, conflictColumns, {{end}}updateColumns, whitelist...)
+func (o *{{$tableNameSingular}}) UpsertG({{if eq .DriverName "postgres"}}updateOnConflict bool, conflictColumns []string, {{end}}updateColumns []string,	whitelist ...string) error {
+	return o.Upsert(boil.GetDB(), {{if eq .DriverName "postgres"}}updateOnConflict, conflictColumns, {{end}}updateColumns, whitelist...)
 }
 
 // UpsertGP attempts an insert, and does an update or ignore on conflict. Panics on error.
-func (o *{{$tableNameSingular}}) UpsertGP({{if ne .DriverName "mysql"}}updateOnConflict bool, conflictColumns []string, {{end}}updateColumns []string,	whitelist ...string) {
-	if err := o.Upsert(boil.GetDB(), {{if ne .DriverName "mysql"}}updateOnConflict, conflictColumns, {{end}}updateColumns, whitelist...); err != nil {
+func (o *{{$tableNameSingular}}) UpsertGP({{if eq .DriverName "postgres"}}updateOnConflict bool, conflictColumns []string, {{end}}updateColumns []string,	whitelist ...string) {
+	if err := o.Upsert(boil.GetDB(), {{if eq .DriverName "postgres"}}updateOnConflict, conflictColumns, {{end}}updateColumns, whitelist...); err != nil {
 		panic(boil.WrapErr(err))
 	}
 }
 
 // UpsertP attempts an insert using an executor, and does an update or ignore on conflict.
 // UpsertP panics on error.
-func (o *{{$tableNameSingular}}) UpsertP(exec boil.Executor, {{if ne .DriverName "mysql"}}updateOnConflict bool, conflictColumns []string, {{end}}updateColumns []string,	whitelist ...string) {
-	if err := o.Upsert(exec, {{if ne .DriverName "mysql"}}updateOnConflict, conflictColumns, {{end}}updateColumns, whitelist...); err != nil {
+func (o *{{$tableNameSingular}}) UpsertP(exec boil.Executor, {{if eq .DriverName "postgres"}}updateOnConflict bool, conflictColumns []string, {{end}}updateColumns []string,	whitelist ...string) {
+	if err := o.Upsert(exec, {{if eq .DriverName "postgres"}}updateOnConflict, conflictColumns, {{end}}updateColumns, whitelist...); err != nil {
 		panic(boil.WrapErr(err))
 	}
 }
 
 // Upsert attempts an insert using an executor, and does an update or ignore on conflict.
-func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if ne .DriverName "mysql"}}updateOnConflict bool, conflictColumns []string, {{end}}updateColumns []string, whitelist ...string) error {
+func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName "postgres"}}updateOnConflict bool, conflictColumns []string, {{end}}updateColumns []string, whitelist ...string) error {
 	if o == nil {
 		return errors.New("{{.PkgName}}: no {{.Table.Name}} provided for upsert")
 	}
@@ -40,7 +39,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if ne .DriverName
 
 	// Build cache key in-line uglily - mysql vs postgres problems
 	buf := strmangle.GetBuffer()
-	{{if ne .DriverName "mysql" -}}
+	{{if eq .DriverName "postgres"}}
 	if updateOnConflict {
 		buf.WriteByte('t')
 	} else {
@@ -73,36 +72,64 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if ne .DriverName
 	var err error
 
 	if !cached {
-		var ret []string
-		whitelist, ret = strmangle.InsertColumnSet(
+		insert, ret := strmangle.InsertColumnSet(
 			{{$varNameSingular}}Columns,
 			{{$varNameSingular}}ColumnsWithDefault,
 			{{$varNameSingular}}ColumnsWithoutDefault,
 			nzDefaults,
 			whitelist,
 		)
+		{{- if eq .DriverName "mssql"}}
+		insert = strmangle.SetComplement(insert, {{$varNameSingular}}ColumnsWithAuto)
+		for i, v := range insert {
+			if strmangle.ContainsAny({{$varNameSingular}}PrimaryKeyColumns, v) && strmangle.ContainsAny({{$varNameSingular}}ColumnsWithDefault, v) {
+				insert = append(insert[:i], insert[i+1:]...)
+			}
+		}
+		if len(insert) == 0 {
+			return errors.New("models: unable to upsert {{.Table.Name}}, could not build insert column list")
+		}
+
+		ret = strmangle.SetMerge(ret, {{$varNameSingular}}ColumnsWithAuto)
+		ret = strmangle.SetMerge(ret, {{$varNameSingular}}ColumnsWithDefault)
+		
+		{{end -}}
 		update := strmangle.UpdateColumnSet(
 			{{$varNameSingular}}Columns,
 			{{$varNameSingular}}PrimaryKeyColumns,
 			updateColumns,
 		)
+
+		{{- if eq .DriverName "mssql"}}
+		update = strmangle.SetComplement(update, {{$varNameSingular}}ColumnsWithAuto)
+		{{end -}}
+
 		if len(update) == 0 {
 			return errors.New("{{.PkgName}}: unable to upsert {{.Table.Name}}, could not build update column list")
 		}
 
-		{{if ne .DriverName "mysql" -}}
+		{{if eq .DriverName "postgres"}}
 		conflict := conflictColumns
 		if len(conflict) == 0 {
 			conflict = make([]string, len({{$varNameSingular}}PrimaryKeyColumns))
 			copy(conflict, {{$varNameSingular}}PrimaryKeyColumns)
 		}
-		cache.query = queries.BuildUpsertQueryPostgres(dialect, "{{$schemaTable}}", updateOnConflict, ret, update, conflict, whitelist)
-		{{- else -}}
-		cache.query = queries.BuildUpsertQueryMySQL(dialect, "{{.Table.Name}}", update, whitelist)
+		cache.query = queries.BuildUpsertQueryPostgres(dialect, "{{$schemaTable}}", updateOnConflict, ret, update, conflict, insert)
+		{{- end -}}
+
+		{{if eq .DriverName "mysql"}}
+		cache.query = queries.BuildUpsertQueryMySQL(dialect, "{{.Table.Name}}", update, insert)
 		cache.retQuery = fmt.Sprintf(
 			"SELECT %s FROM {{.LQ}}{{.Table.Name}}{{.RQ}} WHERE {{whereClause .LQ .RQ 0 .Table.PKey.Columns}}",
 			strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, ret), ","),
 		)
+		{{- end -}}
+
+		{{if eq .DriverName "mssql"}}
+		cache.query = queries.BuildUpsertQueryMSSQL(dialect, "{{.Table.Name}}", {{$varNameSingular}}PrimaryKeyColumns, update, insert, ret)
+
+		whitelist = append({{$varNameSingular}}PrimaryKeyColumns, update...)
+		whitelist = append(whitelist, insert...)
 		{{- end}}
 
 		cache.valueMapping, err = queries.BindMapping({{$varNameSingular}}Type, {{$varNameSingular}}Mapping, whitelist)
@@ -207,5 +234,4 @@ CacheNoHooks:
 	{{- else -}}
 	return nil
 	{{- end}}
-}
-{{- end}}
+}
\ No newline at end of file
diff --git a/templates_test/hooks.tpl b/templates_test/hooks.tpl
index 412ab0c..2cdca44 100644
--- a/templates_test/hooks.tpl
+++ b/templates_test/hooks.tpl
@@ -38,7 +38,6 @@ func {{$varNameSingular}}AfterDeleteHook(e boil.Executor, o *{{$tableNameSingula
 	return nil
 }
 
-{{if ne .DriverName "mssql" -}}
 func {{$varNameSingular}}BeforeUpsertHook(e boil.Executor, o *{{$tableNameSingular}}) error {
 	*o = {{$tableNameSingular}}{}
 	return nil
@@ -48,7 +47,6 @@ func {{$varNameSingular}}AfterUpsertHook(e boil.Executor, o *{{$tableNameSingula
 	*o = {{$tableNameSingular}}{}
 	return nil
 }
-{{- end}}
 
 func test{{$tableNamePlural}}Hooks(t *testing.T) {
 	t.Parallel()
@@ -126,7 +124,6 @@ func test{{$tableNamePlural}}Hooks(t *testing.T) {
 	}
 	{{$varNameSingular}}AfterDeleteHooks = []{{$tableNameSingular}}Hook{}
 
-	{{if ne .DriverName "mssql" -}}
 	Add{{$tableNameSingular}}Hook(boil.BeforeUpsertHook, {{$varNameSingular}}BeforeUpsertHook)
 	if err = o.doBeforeUpsertHooks(nil); err != nil {
 		t.Errorf("Unable to execute doBeforeUpsertHooks: %s", err)
@@ -144,6 +141,5 @@ func test{{$tableNamePlural}}Hooks(t *testing.T) {
 		t.Errorf("Expected AfterUpsertHook function to empty object, but got: %#v", o)
 	}
 	{{$varNameSingular}}AfterUpsertHooks = []{{$tableNameSingular}}Hook{}
-	{{- end}}
 }
 {{- end}}
diff --git a/templates_test/singleton/boil_suites_test.tpl b/templates_test/singleton/boil_suites_test.tpl
index 022d7be..a2ca510 100644
--- a/templates_test/singleton/boil_suites_test.tpl
+++ b/templates_test/singleton/boil_suites_test.tpl
@@ -327,7 +327,7 @@ func TestSliceUpdateAll(t *testing.T) {
   {{end -}}
   {{- end -}}
 }
-{{if ne .DriverName "mssql" -}}
+
 func TestUpsert(t *testing.T) {
   {{- range $index, $table := .Tables}}
   {{- if $table.IsJoinTable -}}
@@ -336,5 +336,4 @@ func TestUpsert(t *testing.T) {
   t.Run("{{$tableName}}", test{{$tableName}}Upsert)
   {{end -}}
   {{- end -}}
-}
-{{- end -}}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/templates_test/upsert.tpl b/templates_test/upsert.tpl
index 25807cf..7e08819 100644
--- a/templates_test/upsert.tpl
+++ b/templates_test/upsert.tpl
@@ -1,4 +1,3 @@
-{{- if ne .DriverName "mssql" -}}
 {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
 {{- $tableNamePlural := .Table.Name | plural | titleCase -}}
 {{- $varNamePlural := .Table.Name | plural | camelCase -}}
@@ -48,5 +47,4 @@ func test{{$tableNamePlural}}Upsert(t *testing.T) {
 	if count != 1 {
 		t.Error("want one record, got:", count)
 	}
-}
-{{- end}}
+}
\ No newline at end of file

From f4b9b2a40627e8906ec9807c33b93585c1be3c6d Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Tue, 21 Mar 2017 13:15:37 +0300
Subject: [PATCH 105/179] Better startIndex calculation

---
 queries/query_builders.go | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/queries/query_builders.go b/queries/query_builders.go
index 7cf753f..2188044 100644
--- a/queries/query_builders.go
+++ b/queries/query_builders.go
@@ -305,12 +305,12 @@ func BuildUpsertQueryMSSQL(dia Dialect, tableName string, primary, update, inser
 	}
 	fmt.Fprint(buf, ")\n")
 
-	startIndex = len(primary) + 1
+	startIndex += len(primary)
 
 	fmt.Fprint(buf, "WHEN MATCHED THEN ")
 	fmt.Fprintf(buf, "UPDATE SET %s\n", strmangle.SetParamNames(string(dia.LQ), string(dia.RQ), startIndex, update))
 
-	startIndex = len(primary) + 1 + len(update)
+	startIndex += len(update)
 
 	fmt.Fprint(buf, "WHEN NOT MATCHED THEN ")
 	fmt.Fprintf(buf, "INSERT (%s) VALUES (%s)",

From 8ef33a112784f7d86bcd6431c3d912c30dee84d8 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Fri, 31 Mar 2017 10:52:54 +0300
Subject: [PATCH 106/179] PkgName in error

---
 templates/17_upsert.tpl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index 70df4c7..92fc4ca 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -87,7 +87,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 			}
 		}
 		if len(insert) == 0 {
-			return errors.New("models: unable to upsert {{.Table.Name}}, could not build insert column list")
+			return errors.New("{{.PkgName}}: unable to upsert {{.Table.Name}}, could not build insert column list")
 		}
 
 		ret = strmangle.SetMerge(ret, {{$varNameSingular}}ColumnsWithAuto)

From 83b935168f754c22a25eef04e3a87d6b1986c8da Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Fri, 31 Mar 2017 10:59:03 +0300
Subject: [PATCH 107/179] Branching with if-else

---
 templates/17_upsert.tpl | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index 92fc4ca..a7a527c 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -115,17 +115,13 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 			copy(conflict, {{$varNameSingular}}PrimaryKeyColumns)
 		}
 		cache.query = queries.BuildUpsertQueryPostgres(dialect, "{{$schemaTable}}", updateOnConflict, ret, update, conflict, insert)
-		{{- end -}}
-
-		{{if eq .DriverName "mysql"}}
+		{{else if eq .DriverName "mysql"}}
 		cache.query = queries.BuildUpsertQueryMySQL(dialect, "{{.Table.Name}}", update, insert)
 		cache.retQuery = fmt.Sprintf(
 			"SELECT %s FROM {{.LQ}}{{.Table.Name}}{{.RQ}} WHERE {{whereClause .LQ .RQ 0 .Table.PKey.Columns}}",
 			strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, ret), ","),
 		)
-		{{- end -}}
-
-		{{if eq .DriverName "mssql"}}
+		{{else if eq .DriverName "mssql"}}
 		cache.query = queries.BuildUpsertQueryMSSQL(dialect, "{{.Table.Name}}", {{$varNameSingular}}PrimaryKeyColumns, update, insert, ret)
 
 		whitelist = append({{$varNameSingular}}PrimaryKeyColumns, update...)

From b4fc4447f803bd12f2961dd1877e39b62a600335 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Fri, 31 Mar 2017 11:03:16 +0300
Subject: [PATCH 108/179] Fixed trim direction

---
 templates/01_types.tpl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/templates/01_types.tpl b/templates/01_types.tpl
index 1f8d015..a1a1ef0 100644
--- a/templates/01_types.tpl
+++ b/templates/01_types.tpl
@@ -6,7 +6,7 @@ var (
 	{{$varNameSingular}}Columns               = []string{{"{"}}{{.Table.Columns | columnNames | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}}
 	{{if eq .DriverName "mssql" -}}
 	{{$varNameSingular}}ColumnsWithAuto = []string{{"{"}}{{.Table.Columns | filterColumnsByAuto true | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
-	{{- end}}
+	{{end -}}
 	{{$varNameSingular}}ColumnsWithoutDefault = []string{{"{"}}{{.Table.Columns | filterColumnsByDefault false | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
 	{{$varNameSingular}}ColumnsWithDefault    = []string{{"{"}}{{.Table.Columns | filterColumnsByDefault true | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
 	{{$varNameSingular}}PrimaryKeyColumns     = []string{{"{"}}{{.Table.PKey.Columns | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}}

From b10df110a0240c5674a82c116234b36c02e4f6ce Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Fri, 31 Mar 2017 11:05:52 +0300
Subject: [PATCH 109/179] Newline at end of file

---
 templates/17_upsert.tpl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index a7a527c..fb9c2d0 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -230,4 +230,4 @@ CacheNoHooks:
 	{{- else -}}
 	return nil
 	{{- end}}
-}
\ No newline at end of file
+}

From dbf897977a0a0ac73e4c4408b56fb7fe7bf88b3d Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Fri, 31 Mar 2017 11:07:30 +0300
Subject: [PATCH 110/179] Newline at end of file

---
 templates_test/singleton/boil_suites_test.tpl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/templates_test/singleton/boil_suites_test.tpl b/templates_test/singleton/boil_suites_test.tpl
index a2ca510..08a5e21 100644
--- a/templates_test/singleton/boil_suites_test.tpl
+++ b/templates_test/singleton/boil_suites_test.tpl
@@ -336,4 +336,4 @@ func TestUpsert(t *testing.T) {
   t.Run("{{$tableName}}", test{{$tableName}}Upsert)
   {{end -}}
   {{- end -}}
-}
\ No newline at end of file
+}

From 874d2ed2e6734f6f91aa014c0ad44dfdba07d638 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Fri, 31 Mar 2017 11:24:11 +0300
Subject: [PATCH 111/179] Fixed type for non-nullable uniqueidentifier, xml

---
 bdb/drivers/mssql.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 9d20d0f..e8a0b5f 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -343,7 +343,7 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 		case "timestamp", "rowversion":
 			c.Type = "[]byte"
 		case "uniqueidentifier", "xml":
-			c.Type = "null.String"
+			c.Type = "string"
 		default:
 			c.Type = "string"
 		}

From dfbcef7fe33c358d5898378bf94584006a20061e Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Fri, 31 Mar 2017 11:27:34 +0300
Subject: [PATCH 112/179] Fixed typo and combined variables declaration

---
 templates/15_insert.tpl | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index bb72404..429154c 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -75,21 +75,20 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 			{{end -}}
 		}
 
-		queryOutput := ""
-		qyeryReturning := ""
+		var queryOutput, queryReturning string
 
 		if len(cache.retMapping) != 0 {
 			{{if .UseLastInsertID -}}
 			cache.retQuery = fmt.Sprintf("SELECT {{.LQ}}%s{{.RQ}} FROM {{$schemaTable}} WHERE %s", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"), strmangle.WhereClause("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns))
 			{{else -}}
 				{{if ne .DriverName "mssql" -}}
-			qyeryReturning = fmt.Sprintf(" RETURNING {{.LQ}}%s{{.RQ}}", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"))
+			queryReturning = fmt.Sprintf(" RETURNING {{.LQ}}%s{{.RQ}}", strings.Join(returnColumns, "{{.RQ}},{{.LQ}}"))
 				{{else -}}
 			queryOutput = fmt.Sprintf("OUTPUT INSERTED.{{.LQ}}%s{{.RQ}} ", strings.Join(returnColumns, "{{.RQ}},INSERTED.{{.LQ}}"))
 				{{end -}}
 			{{- end}}
 		}
-		cache.query = fmt.Sprintf(cache.query, queryOutput, qyeryReturning)
+		cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning)
 	}
 
 	value := reflect.Indirect(reflect.ValueOf(o))

From a4ba4b6e9d903bc8a1157218696fb7bb3ba2a009 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Fri, 31 Mar 2017 11:39:12 +0300
Subject: [PATCH 113/179] Uniqueidentifier now treated as uuid

---
 bdb/drivers/mssql.go   | 10 ++++++++--
 randomize/randomize.go |  8 ++++----
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index e8a0b5f..3698069 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -313,8 +313,11 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			c.Type = "null.Bytes"
 		case "timestamp", "rowversion":
 			c.Type = "null.Bytes"
-		case "uniqueidentifier", "xml":
+		case "xml":
 			c.Type = "null.String"
+		case "uniqueidentifier":
+			c.Type = "null.String"
+			c.DBType = "uuid"
 		default:
 			c.Type = "null.String"
 		}
@@ -342,8 +345,11 @@ func (m *MSSQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			c.Type = "[]byte"
 		case "timestamp", "rowversion":
 			c.Type = "[]byte"
-		case "uniqueidentifier", "xml":
+		case "xml":
 			c.Type = "string"
+		case "uniqueidentifier":
+			c.Type = "string"
+			c.DBType = "uuid"
 		default:
 			c.Type = "string"
 		}
diff --git a/randomize/randomize.go b/randomize/randomize.go
index 2af945d..59f7eff 100644
--- a/randomize/randomize.go
+++ b/randomize/randomize.go
@@ -52,7 +52,7 @@ var (
 	rgxValidTime     = regexp.MustCompile(`[2-9]+`)
 
 	validatedTypes = []string{
-		"inet", "line", "uuid", "uniqueidentifier", "interval", "mediumint",
+		"inet", "line", "uuid", "interval", "mediumint",
 		"json", "jsonb", "box", "cidr", "circle",
 		"lseg", "macaddr", "path", "pg_lsn", "point",
 		"polygon", "txid_snapshot", "money", "hstore",
@@ -195,7 +195,7 @@ func randomizeField(s *Seed, field reflect.Value, fieldType string, canBeNull bo
 					field.Set(reflect.ValueOf(value))
 					return nil
 				}
-				if fieldType == "uuid" || fieldType == "uniqueidentifier" {
+				if fieldType == "uuid" {
 					value = null.NewString(uuid.NewV4().String(), true)
 					field.Set(reflect.ValueOf(value))
 					return nil
@@ -268,7 +268,7 @@ func randomizeField(s *Seed, field reflect.Value, fieldType string, canBeNull bo
 					field.Set(reflect.ValueOf(value))
 					return nil
 				}
-				if fieldType == "uuid" || fieldType == "uniqueidentifier" {
+				if fieldType == "uuid" {
 					value = uuid.NewV4().String()
 					field.Set(reflect.ValueOf(value))
 					return nil
@@ -390,7 +390,7 @@ func getArrayRandValue(s *Seed, typ reflect.Type, fieldType string) interface{}
 			value := strconv.Itoa((s.nextInt()%26)+2) + " days"
 			return types.StringArray{value, value}
 		}
-		if fieldType == "uuid" || fieldType == "uniqueidentifier" {
+		if fieldType == "uuid" {
 			value := uuid.NewV4().String()
 			return types.StringArray{value, value}
 		}

From f94fa547e714fe0ab7c2e6dcdc2b00cfd3a7feb0 Mon Sep 17 00:00:00 2001
From: Aric Huang <arichuang@gmail.com>
Date: Fri, 31 Mar 2017 15:02:32 -0700
Subject: [PATCH 114/179] (fix) typo in README

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index b2d8ae1..8893bc7 100644
--- a/README.md
+++ b/README.md
@@ -408,7 +408,7 @@ much benefit over it.
 
 **Method 3: Embedding**
 
-This pattern is not for the feint of heart, what it provides in benefits it
+This pattern is not for the faint of heart, what it provides in benefits it
 more than makes up for in downsides. It's possible to embed the SQLBoiler
 structs inside your own to enhance them. However it's subject to easy breakages
 and a dependency on these additional objects. It can also introduce

From e1dfd0bb1e890cf4d4dfee5e337e5fa264f08361 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sat, 1 Apr 2017 18:59:22 +0300
Subject: [PATCH 115/179] Newline at end of file

---
 templates_test/upsert.tpl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/templates_test/upsert.tpl b/templates_test/upsert.tpl
index 7e08819..f9c351e 100644
--- a/templates_test/upsert.tpl
+++ b/templates_test/upsert.tpl
@@ -47,4 +47,4 @@ func test{{$tableNamePlural}}Upsert(t *testing.T) {
 	if count != 1 {
 		t.Error("want one record, got:", count)
 	}
-}
\ No newline at end of file
+}

From b6d0a5142ac4db4a3f1e284da1655dcef1ddb70b Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sat, 1 Apr 2017 20:16:05 +0300
Subject: [PATCH 116/179] Removed special case for mssql

---
 templates_test/insert.tpl | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/templates_test/insert.tpl b/templates_test/insert.tpl
index 82f87b6..e3446f0 100644
--- a/templates_test/insert.tpl
+++ b/templates_test/insert.tpl
@@ -41,11 +41,7 @@ func test{{$tableNamePlural}}InsertWhitelist(t *testing.T) {
 
 	tx := MustTx(boil.Begin())
 	defer tx.Rollback()
-	{{if ne .DriverName "mssql"}}
-	if err = {{$varNameSingular}}.Insert(tx, {{$varNameSingular}}Columns...); err != nil {
-	{{- else -}}
 	if err = {{$varNameSingular}}.Insert(tx, {{$varNameSingular}}ColumnsWithoutDefault...); err != nil {
-	{{- end}}
 		t.Error(err)
 	}
 

From 783e7a82b34de24a12c071bd53a3ad72a5da6a78 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sat, 1 Apr 2017 20:30:40 +0300
Subject: [PATCH 117/179] Choosing StartIndex at template time

---
 templates/16_update.tpl | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index 2ee87cc..7b6e585 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -171,15 +171,9 @@ func (o {{$tableNameSingular}}Slice) UpdateAll(exec boil.Executor, cols M) error
 		strmangle.Placeholders(dialect.IndexPlaceholders, len(o) * len({{$varNameSingular}}PrimaryKeyColumns), len(colNames)+1, len({{$varNameSingular}}PrimaryKeyColumns)),
 	)
 	{{- else -}}
-	startIndex := len(colNames) + 1
-
-	if !dialect.IndexPlaceholders {
-		startIndex = 0
-	}
-
 	sql := fmt.Sprintf("UPDATE {{$schemaTable}} SET %s WHERE %s",
 		strmangle.SetParamNames("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, colNames),
-		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), startIndex, {{$varNameSingular}}PrimaryKeyColumns, len(o)))
+		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), {{if .Dialect.IndexPlaceholders}}len(colNames)+1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns, len(o)))
 	{{- end}}
 
 	if boil.DebugMode {

From 178d925c24c4fddefbf6c273847775e483e1fd0b Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sat, 1 Apr 2017 21:00:13 +0300
Subject: [PATCH 118/179] Generic Update statement

---
 templates/16_update.tpl | 9 +--------
 1 file changed, 1 insertion(+), 8 deletions(-)

diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index 7b6e585..708723e 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -164,17 +164,10 @@ func (o {{$tableNameSingular}}Slice) UpdateAll(exec boil.Executor, cols M) error
 		pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), {{$varNameSingular}}PrimaryKeyMapping)
 		args = append(args, pkeyArgs...)
 	}
-	{{if ne .DriverName "mssql" -}}
-	sql := fmt.Sprintf(
-		"UPDATE {{$schemaTable}} SET %s WHERE ({{.LQ}}{{.Table.PKey.Columns | join (printf "%s,%s" .LQ .RQ)}}{{.RQ}}) IN (%s)",
-		strmangle.SetParamNames("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, colNames),
-		strmangle.Placeholders(dialect.IndexPlaceholders, len(o) * len({{$varNameSingular}}PrimaryKeyColumns), len(colNames)+1, len({{$varNameSingular}}PrimaryKeyColumns)),
-	)
-	{{- else -}}
+	
 	sql := fmt.Sprintf("UPDATE {{$schemaTable}} SET %s WHERE %s",
 		strmangle.SetParamNames("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, colNames),
 		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), {{if .Dialect.IndexPlaceholders}}len(colNames)+1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns, len(o)))
-	{{- end}}
 
 	if boil.DebugMode {
 		fmt.Fprintln(boil.DebugWriter, sql)

From f913d5e791b08b3cb862db41ee4a03815f3de0a6 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sat, 1 Apr 2017 21:08:29 +0300
Subject: [PATCH 119/179] Generic Delete statement

---
 templates/18_delete.tpl | 18 ++----------------
 1 file changed, 2 insertions(+), 16 deletions(-)

diff --git a/templates/18_delete.tpl b/templates/18_delete.tpl
index 61282aa..f2ddbb6 100644
--- a/templates/18_delete.tpl
+++ b/templates/18_delete.tpl
@@ -135,22 +135,8 @@ func (o {{$tableNameSingular}}Slice) DeleteAll(exec boil.Executor) error {
 		args = append(args, pkeyArgs...)
 	}
 
-	{{if ne .DriverName "mssql" -}}
-	sql := fmt.Sprintf(
-		"DELETE FROM {{$schemaTable}} WHERE (%s) IN (%s)",
-		strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, {{$varNameSingular}}PrimaryKeyColumns), ","),
-		strmangle.Placeholders(dialect.IndexPlaceholders, len(o) * len({{$varNameSingular}}PrimaryKeyColumns), 1, len({{$varNameSingular}}PrimaryKeyColumns)),
-	)
-	{{- else -}}
-	startIndex := 1
-
-	if !dialect.IndexPlaceholders {
-		startIndex = 0
-	}
-
-	sql := "DELETE FROM {{$schemaTable}}  WHERE " +
-		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), startIndex, {{$varNameSingular}}PrimaryKeyColumns, len(o))
-	{{- end}}
+	sql := "DELETE FROM {{$schemaTable}} WHERE " +
+		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns, len(o))
 
 	if boil.DebugMode {
 		fmt.Fprintln(boil.DebugWriter, sql)

From b2acda8ade28b1ee1c51aaa083bd8a594b586f40 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sat, 1 Apr 2017 21:11:01 +0300
Subject: [PATCH 120/179] Generic Select statement in Reload

---
 templates/19_reload.tpl | 16 +---------------
 1 file changed, 1 insertion(+), 15 deletions(-)

diff --git a/templates/19_reload.tpl b/templates/19_reload.tpl
index ff656f1..b1201b8 100644
--- a/templates/19_reload.tpl
+++ b/templates/19_reload.tpl
@@ -79,22 +79,8 @@ func (o *{{$tableNameSingular}}Slice) ReloadAll(exec boil.Executor) error {
 		args = append(args, pkeyArgs...)
 	}
 
-	{{if ne .DriverName "mssql" -}}
-	sql := fmt.Sprintf(
-		"SELECT {{$schemaTable}}.* FROM {{$schemaTable}} WHERE (%s) IN (%s)",
-		strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, {{$varNameSingular}}PrimaryKeyColumns), ","),
-		strmangle.Placeholders(dialect.IndexPlaceholders, len(*o) * len({{$varNameSingular}}PrimaryKeyColumns), 1, len({{$varNameSingular}}PrimaryKeyColumns)),
-	)
-	{{- else -}}
-	startIndex := 1
-
-	if !dialect.IndexPlaceholders {
-		startIndex = 0
-	}
-
 	sql := "SELECT {{$schemaTable}}.* FROM {{$schemaTable}} WHERE " +
-		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), startIndex, {{$varNameSingular}}PrimaryKeyColumns, len(*o))
-	{{- end}}
+		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns, len(*o))
 
 	q := queries.Raw(exec, sql, args...)
 

From fd2c7ad764db44de2307fdcc842fe4f83ba5b58e Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sun, 2 Apr 2017 12:27:33 +0300
Subject: [PATCH 121/179] Fixed Upsert statement for postgres, mysql

---
 templates/17_upsert.tpl | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index fb9c2d0..e45a87e 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -79,7 +79,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 			nzDefaults,
 			whitelist,
 		)
-		{{- if eq .DriverName "mssql"}}
+		{{if eq .DriverName "mssql" -}}
 		insert = strmangle.SetComplement(insert, {{$varNameSingular}}ColumnsWithAuto)
 		for i, v := range insert {
 			if strmangle.ContainsAny({{$varNameSingular}}PrimaryKeyColumns, v) && strmangle.ContainsAny({{$varNameSingular}}ColumnsWithDefault, v) {
@@ -93,17 +93,16 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 		ret = strmangle.SetMerge(ret, {{$varNameSingular}}ColumnsWithAuto)
 		ret = strmangle.SetMerge(ret, {{$varNameSingular}}ColumnsWithDefault)
 		
-		{{end -}}
+		{{end}}
 		update := strmangle.UpdateColumnSet(
 			{{$varNameSingular}}Columns,
 			{{$varNameSingular}}PrimaryKeyColumns,
 			updateColumns,
 		)
-
-		{{- if eq .DriverName "mssql"}}
+		{{if eq .DriverName "mssql" -}}
 		update = strmangle.SetComplement(update, {{$varNameSingular}}ColumnsWithAuto)
 		{{end -}}
-
+		
 		if len(update) == 0 {
 			return errors.New("{{.PkgName}}: unable to upsert {{.Table.Name}}, could not build update column list")
 		}
@@ -128,7 +127,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 		whitelist = append(whitelist, insert...)
 		{{- end}}
 
-		cache.valueMapping, err = queries.BindMapping({{$varNameSingular}}Type, {{$varNameSingular}}Mapping, whitelist)
+		cache.valueMapping, err = queries.BindMapping({{$varNameSingular}}Type, {{$varNameSingular}}Mapping, {{if eq .DriverName "mssql"}}whitelist{{else}}insert{{end}})
 		if err != nil {
 			return err
 		}

From 4560da9bd1c0f816d1bf624f762481a986538464 Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Sun, 2 Apr 2017 12:48:29 +0300
Subject: [PATCH 122/179] Fixed comment for TableNames

---
 bdb/drivers/mssql.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 3698069..cb3290a 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -75,7 +75,7 @@ func (m *MSSQLDriver) UseTopClause() bool {
 
 // TableNames connects to the postgres database and
 // retrieves all table names from the information_schema where the
-// table schema is public.
+// table schema is schema. It uses a whitelist and blacklist.
 func (m *MSSQLDriver) TableNames(schema string, whitelist, blacklist []string) ([]string, error) {
 	var names []string
 

From 3d1f3fc60936a7d50b0c6e559b645331466f1d28 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Sun, 2 Apr 2017 09:40:08 -0700
Subject: [PATCH 123/179] Use different schema names for different drivers

---
 main.go | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/main.go b/main.go
index a2f9396..acc7b1e 100644
--- a/main.go
+++ b/main.go
@@ -73,7 +73,7 @@ func main() {
 
 	// Set up the cobra root command flags
 	rootCmd.PersistentFlags().StringP("output", "o", "models", "The name of the folder to output to")
-	rootCmd.PersistentFlags().StringP("schema", "s", "public", "The name of your database schema, for databases that support real schemas")
+	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")
 	rootCmd.PersistentFlags().StringP("basedir", "", "", "The base directory has the templates and templates_test folders")
 	rootCmd.PersistentFlags().StringSliceP("blacklist", "b", nil, "Do not include these tables in your generated package")
@@ -202,6 +202,10 @@ func preRun(cmd *cobra.Command, args []string) error {
 			viper.Set("postgres.port", cmdConfig.Postgres.Port)
 		}
 
+		if len(cmdConfig.Schema) == 0 {
+			cmdConfig.Schema = "public"
+		}
+
 		err = vala.BeginValidation().Validate(
 			vala.StringNotEmpty(cmdConfig.Postgres.User, "postgres.user"),
 			vala.StringNotEmpty(cmdConfig.Postgres.Host, "postgres.host"),
@@ -280,6 +284,10 @@ func preRun(cmd *cobra.Command, args []string) error {
 			viper.Set("mssql.port", cmdConfig.MSSQL.Port)
 		}
 
+		if len(cmdConfig.Schema) == 0 {
+			cmdConfig.Schema = "dbo"
+		}
+
 		err = vala.BeginValidation().Validate(
 			vala.StringNotEmpty(cmdConfig.MSSQL.User, "mssql.user"),
 			vala.StringNotEmpty(cmdConfig.MSSQL.Host, "mssql.host"),

From 91950e711e186e6911c7129a4de91ca2d0e9355d Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 4 Apr 2017 17:46:51 -0700
Subject: [PATCH 124/179] Add slack badge to readme

---
 README.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.md b/README.md
index 8893bc7..3960d81 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,7 @@
 
 [![License](https://img.shields.io/badge/license-BSD-blue.svg)](https://github.com/vattle/sqlboiler/blob/master/LICENSE)
 [![GoDoc](https://godoc.org/github.com/vattle/sqlboiler?status.svg)](https://godoc.org/github.com/vattle/sqlboiler)
+[![Slack](https://img.shields.io/badge/slack-%23general-lightgrey.svg)](https://sqlboiler.from-the.cloud)
 [![CircleCI](https://circleci.com/gh/vattle/sqlboiler.svg?style=shield)](https://circleci.com/gh/vattle/sqlboiler)
 [![Go Report Card](https://goreportcard.com/badge/vattle/sqlboiler)](http://goreportcard.com/report/vattle/sqlboiler)
 

From d13410617fc6eb2d385808a4ce74f9611b13fd3e Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 4 Apr 2017 19:40:12 -0700
Subject: [PATCH 125/179] Correct whitespace errors

---
 templates/17_upsert.tpl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index e45a87e..f3d51e7 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -92,7 +92,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 
 		ret = strmangle.SetMerge(ret, {{$varNameSingular}}ColumnsWithAuto)
 		ret = strmangle.SetMerge(ret, {{$varNameSingular}}ColumnsWithDefault)
-		
+
 		{{end}}
 		update := strmangle.UpdateColumnSet(
 			{{$varNameSingular}}Columns,
@@ -102,7 +102,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 		{{if eq .DriverName "mssql" -}}
 		update = strmangle.SetComplement(update, {{$varNameSingular}}ColumnsWithAuto)
 		{{end -}}
-		
+
 		if len(update) == 0 {
 			return errors.New("{{.PkgName}}: unable to upsert {{.Table.Name}}, could not build update column list")
 		}

From 10cfe749891641f5002c568684d1a9b913e631cd Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 4 Apr 2017 19:42:49 -0700
Subject: [PATCH 126/179] Fix a bug that could occur on no-field inserts

---
 templates/15_insert.tpl | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index 429154c..870e20d 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -86,9 +86,12 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 				{{else -}}
 			queryOutput = fmt.Sprintf("OUTPUT INSERTED.{{.LQ}}%s{{.RQ}} ", strings.Join(returnColumns, "{{.RQ}},INSERTED.{{.LQ}}"))
 				{{end -}}
-			{{- end}}
+			{{end -}}
+		}
+
+		if len(wl) != 0 {
+			cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning)
 		}
-		cache.query = fmt.Sprintf(cache.query, queryOutput, queryReturning)
 	}
 
 	value := reflect.Indirect(reflect.ValueOf(o))

From 0818af0e2607dc3a9d9f0686d67bac3984855b93 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Tue, 4 Apr 2017 19:44:36 -0700
Subject: [PATCH 127/179] Don't use XSlice where unneeded.

- In the bowels of the eager loading we weave in and out of reflection,
  but we should not care about using XSlice unless it's going back to
  the user. This change makes it so the XSlice is only used where it
  matters, everywhere else is *[]*X to avoid type assertion errors from
  being able to have either or come into the Load() functions.
- Fix #124
---
 templates/03_finishers.tpl                     | 2 +-
 templates/07_relationship_to_one_eager.tpl     | 3 +--
 templates/08_relationship_one_to_one_eager.tpl | 3 +--
 templates/09_relationship_to_many_eager.tpl    | 3 +--
 templates_test/relationship_one_to_one.tpl     | 2 +-
 templates_test/relationship_to_many.tpl        | 2 +-
 templates_test/relationship_to_one.tpl         | 2 +-
 7 files changed, 7 insertions(+), 10 deletions(-)

diff --git a/templates/03_finishers.tpl b/templates/03_finishers.tpl
index 429a276..0cc7e78 100644
--- a/templates/03_finishers.tpl
+++ b/templates/03_finishers.tpl
@@ -45,7 +45,7 @@ func (q {{$varNameSingular}}Query) AllP() {{$tableNameSingular}}Slice {
 
 // All returns all {{$tableNameSingular}} records from the query.
 func (q {{$varNameSingular}}Query) All() ({{$tableNameSingular}}Slice, error) {
-	var o {{$tableNameSingular}}Slice
+	var o []*{{$tableNameSingular}}
 
 	err := q.Bind(&o)
 	if err != nil {
diff --git a/templates/07_relationship_to_one_eager.tpl b/templates/07_relationship_to_one_eager.tpl
index 4af84ca..dd1481a 100644
--- a/templates/07_relationship_to_one_eager.tpl
+++ b/templates/07_relationship_to_one_eager.tpl
@@ -5,7 +5,6 @@
 		{{- $txt := txtsFromFKey $dot.Tables $dot.Table . -}}
 		{{- $varNameSingular := $dot.Table.Name | singular | camelCase -}}
 		{{- $arg := printf "maybe%s" $txt.LocalTable.NameGo -}}
-		{{- $slice := printf "%sSlice" $txt.LocalTable.NameGo}}
 // Load{{$txt.Function.Name}} allows an eager lookup of values, cached into the
 // loaded structs of the objects.
 func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singular bool, {{$arg}} interface{}) error {
@@ -16,7 +15,7 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 	if singular {
 		object = {{$arg}}.(*{{$txt.LocalTable.NameGo}})
 	} else {
-		slice = *{{$arg}}.(*{{$slice}})
+		slice = *{{$arg}}.(*[]*{{$txt.LocalTable.NameGo}})
 		count = len(slice)
 	}
 
diff --git a/templates/08_relationship_one_to_one_eager.tpl b/templates/08_relationship_one_to_one_eager.tpl
index 7363b69..37d1af0 100644
--- a/templates/08_relationship_one_to_one_eager.tpl
+++ b/templates/08_relationship_one_to_one_eager.tpl
@@ -5,7 +5,6 @@
 		{{- $txt := txtsFromOneToOne $dot.Tables $dot.Table . -}}
 		{{- $varNameSingular := $dot.Table.Name | singular | camelCase -}}
 		{{- $arg := printf "maybe%s" $txt.LocalTable.NameGo -}}
-		{{- $slice := printf "%sSlice" $txt.LocalTable.NameGo}}
 // Load{{$txt.Function.Name}} allows an eager lookup of values, cached into the
 // loaded structs of the objects.
 func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singular bool, {{$arg}} interface{}) error {
@@ -16,7 +15,7 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 	if singular {
 		object = {{$arg}}.(*{{$txt.LocalTable.NameGo}})
 	} else {
-		slice = *{{$arg}}.(*{{$slice}})
+		slice = *{{$arg}}.(*[]*{{$txt.LocalTable.NameGo}})
 		count = len(slice)
 	}
 
diff --git a/templates/09_relationship_to_many_eager.tpl b/templates/09_relationship_to_many_eager.tpl
index f1a7f5d..1603188 100644
--- a/templates/09_relationship_to_many_eager.tpl
+++ b/templates/09_relationship_to_many_eager.tpl
@@ -5,7 +5,6 @@
 		{{- $varNameSingular := $dot.Table.Name | singular | camelCase -}}
 		{{- $txt := txtsFromToMany $dot.Tables $dot.Table . -}}
 		{{- $arg := printf "maybe%s" $txt.LocalTable.NameGo -}}
-		{{- $slice := printf "%sSlice" $txt.LocalTable.NameGo -}}
 		{{- $schemaForeignTable := .ForeignTable | $dot.SchemaTable}}
 // Load{{$txt.Function.Name}} allows an eager lookup of values, cached into the
 // loaded structs of the objects.
@@ -17,7 +16,7 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 	if singular {
 		object = {{$arg}}.(*{{$txt.LocalTable.NameGo}})
 	} else {
-		slice = *{{$arg}}.(*{{$slice}})
+		slice = *{{$arg}}.(*[]*{{$txt.LocalTable.NameGo}})
 		count = len(slice)
 	}
 
diff --git a/templates_test/relationship_one_to_one.tpl b/templates_test/relationship_one_to_one.tpl
index 4e253e5..27c13ef 100644
--- a/templates_test/relationship_one_to_one.tpl
+++ b/templates_test/relationship_one_to_one.tpl
@@ -50,7 +50,7 @@ func test{{$txt.LocalTable.NameGo}}OneToOne{{$txt.ForeignTable.NameGo}}Using{{$t
 	}
 
 	slice := {{$txt.LocalTable.NameGo}}Slice{&local}
-	if err = local.L.Load{{$txt.Function.Name}}(tx, false, &slice); err != nil {
+	if err = local.L.Load{{$txt.Function.Name}}(tx, false, (*[]*{{$txt.LocalTable.NameGo}})(&slice)); err != nil {
 		t.Fatal(err)
 	}
 	if local.R.{{$txt.Function.Name}} == nil {
diff --git a/templates_test/relationship_to_many.tpl b/templates_test/relationship_to_many.tpl
index 0080688..0402609 100644
--- a/templates_test/relationship_to_many.tpl
+++ b/templates_test/relationship_to_many.tpl
@@ -87,7 +87,7 @@ func test{{$txt.LocalTable.NameGo}}ToMany{{$txt.Function.Name}}(t *testing.T) {
 	}
 
 	slice := {{$txt.LocalTable.NameGo}}Slice{&a}
-	if err = a.L.Load{{$txt.Function.Name}}(tx, false, &slice); err != nil {
+	if err = a.L.Load{{$txt.Function.Name}}(tx, false, (*[]*{{$txt.LocalTable.NameGo}})(&slice)); err != nil {
 		t.Fatal(err)
 	}
 	if got := len(a.R.{{$txt.Function.Name}}); got != 2 {
diff --git a/templates_test/relationship_to_one.tpl b/templates_test/relationship_to_one.tpl
index 3c66bf7..e95c61a 100644
--- a/templates_test/relationship_to_one.tpl
+++ b/templates_test/relationship_to_one.tpl
@@ -50,7 +50,7 @@ func test{{$txt.LocalTable.NameGo}}ToOne{{$txt.ForeignTable.NameGo}}Using{{$txt.
 	}
 
 	slice := {{$txt.LocalTable.NameGo}}Slice{&local}
-	if err = local.L.Load{{$txt.Function.Name}}(tx, false, &slice); err != nil {
+	if err = local.L.Load{{$txt.Function.Name}}(tx, false, (*[]*{{$txt.LocalTable.NameGo}})(&slice)); err != nil {
 		t.Fatal(err)
 	}
 	if local.R.{{$txt.Function.Name}} == nil {

From 91a798d9afe9c1479620cae5d1132bfae5b42619 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20Mrozek?= <Michsior14@users.noreply.github.com>
Date: Sun, 16 Apr 2017 20:00:43 +0200
Subject: [PATCH 128/179] Update global.go

---
 boil/global.go | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/boil/global.go b/boil/global.go
index f357d61..03c574b 100644
--- a/boil/global.go
+++ b/boil/global.go
@@ -1,6 +1,7 @@
 package boil
 
 import (
+	"io"
 	"os"
 	"time"
 )
@@ -20,7 +21,7 @@ var (
 var DebugMode = false
 
 // DebugWriter is where the debug output will be sent if DebugMode is true
-var DebugWriter = os.Stdout
+var DebugWriter io.Writer = os.Stdout
 
 // SetDB initializes the database handle for all template db interactions
 func SetDB(db Executor) {

From 5a3389441299cbd2d42b17f9b5ff45a53bee9a9a Mon Sep 17 00:00:00 2001
From: Aaron <aaron@bettercoder.net>
Date: Sun, 16 Apr 2017 11:57:06 -0700
Subject: [PATCH 129/179] Add contribution guidelines

---
 CONTRIBUTING.md | 60 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)
 create mode 100644 CONTRIBUTING.md

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..8ce4412
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,60 @@
+# Contributing
+
+Thanks for your interest in contributing to SQLBoiler!
+
+We have a very lightweight process and aim to keep it that way.
+Read the sections for the piece you're interested in and go from
+there.
+
+If you need quick communication we're usually on [Slack](https://sqlboiler.from-the.cloud).
+
+# New Code / Features
+
+## Small Change
+
+#### TLDR
+
+1. Open PR against **dev** branch with explanation
+1. Participate in Github Code Review
+
+#### Long version
+
+For code that requires little to no discussion, please just open a pull request with some
+explanation against the **dev** branch. All code goes through dev before going out in a release.
+
+## Bigger Change
+
+#### TLDR
+
+1. Start proposal of idea in Github issue
+1. After design concensus, open PR with the work against the **dev** branch
+1. Participate in Github Code Review
+
+#### Long version
+
+If however you're working on something bigger, it's usually better to check with us on the idea
+before starting on a pull request, just so there's no time wasted in redoing/refactoring or being
+outright rejected because the PR is at odds with the design. The best way to accomplish this is to
+open an issue to discuss it. It can always start as a Slack conversation but should eventually end
+up as an issue to avoid penalizing the rest of the users for not being on Slack. Once we agree on
+the way to do something, then open the PR against the **dev** branch and we'll commence code review
+with the Github code review tools. Then it will be merged into dev, and later go out in a release.
+
+# Bugs
+
+Issues should be filed on Github, simply use the template provided and fill in detail. If there's
+more information you feel you should give use your best judgement and add it in, the more the better.
+See the section below for information on providing database schemas.
+
+Bugs that have responses from contributors but no action from those who opened them after a time
+will be closed with the comment: "Stale"
+
+## Schemas
+
+A database schema can help us fix generation issues very quickly. However not everyone is willing to part
+with their database schema for various reasons and that's fine. Instead of providing the schema please
+then provide a subset of your database (you can munge the names so as to be unrecognizable) that can
+help us reproduce the problem.
+
+*Note:* Your schema information is included in the output from `--debug`, so be careful giving this
+information out publicly on a Github issue if you're sensitive about this.

From 6a0817d37db9533d16a0a35deb3333037859ba70 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Sun, 23 Apr 2017 14:28:21 -0700
Subject: [PATCH 130/179] Update benchmark section

---
 README.md | 119 +++++++++++++++++++++++++++++++++---------------------
 1 file changed, 73 insertions(+), 46 deletions(-)

diff --git a/README.md b/README.md
index 3960d81..214926d 100644
--- a/README.md
+++ b/README.md
@@ -1253,51 +1253,78 @@ generator is located at: https://github.com/vattle/sqlboiler
 
 If you'd like to run the benchmarks yourself check out our [boilbench](https://github.com/vattle/boilbench) repo.
 
-Here are the results (lower is better):
-
-`go test -bench . -benchmem`
-```
-BenchmarkGORMDelete/gorm-8     	    100000	     15364 ns/op	    5395 B/op	     113 allocs/op
-BenchmarkGORPDelete/gorp-8     	   1000000	      1703 ns/op	     304 B/op	      12 allocs/op
-BenchmarkXORMDelete/xorm-8     	    100000	     14733 ns/op	    3634 B/op	     107 allocs/op
-BenchmarkBoilDelete/boil-8     	   2000000	       986 ns/op	     120 B/op	       7 allocs/op
-
-BenchmarkGORMInsert/gorm-8     	    100000	     19197 ns/op	    8054 B/op	     161 allocs/op
-BenchmarkGORPInsert/gorp-8     	    500000	      3413 ns/op	    1008 B/op	      32 allocs/op
-BenchmarkXORMInsert/xorm-8     	    100000	     15428 ns/op	    5836 B/op	     131 allocs/op
-BenchmarkBoilInsert/boil-8     	    500000	      3041 ns/op	     568 B/op	      21 allocs/op
-
-BenchmarkGORMSelectAll/gorm-8  	     20000	     85422 ns/op	   29912 B/op	     511 allocs/op
-BenchmarkGORPSelectAll/gorp-8  	     50000	     35824 ns/op	    8837 B/op	     312 allocs/op
-BenchmarkXORMSelectAll/xorm-8  	     30000	     58843 ns/op	   13805 B/op	     298 allocs/op
-BenchmarkBoilSelectAll/boil-8  	    100000	     13844 ns/op	    2840 B/op	      61 allocs/op
-
-BenchmarkGORMSelectSubset/gorm-8     10000	    100714 ns/op	   30875 B/op	     517 allocs/op
-BenchmarkGORPSelectSubset/gorp-8     30000	     43547 ns/op	    8837 B/op	     312 allocs/op
-BenchmarkXORMSelectSubset/xorm-8     30000	     48128 ns/op	   12989 B/op	     282 allocs/op
-BenchmarkBoilSelectSubset/boil-8    100000	     12316 ns/op	    2977 B/op	      65 allocs/op
-
-BenchmarkGORMSelectComplex/gorm-8    10000	    133598 ns/op	   49398 B/op	     772 allocs/op
-BenchmarkGORPSelectComplex/gorp-8    50000	     40588 ns/op	    9037 B/op	     321 allocs/op
-BenchmarkXORMSelectComplex/xorm-8    30000	     56367 ns/op	   14174 B/op	     313 allocs/op
-BenchmarkBoilSelectComplex/boil-8   100000	     16941 ns/op	    3821 B/op	      95 allocs/op
-
-BenchmarkGORMUpdate/gorm-8           50000	     25406 ns/op	    9710 B/op	     195 allocs/op
-BenchmarkGORPUpdate/gorp-8          300000	      3614 ns/op	    1152 B/op	      34 allocs/op
-BenchmarkXORMUpdate/xorm-8          100000	     17510 ns/op	    4458 B/op	     132 allocs/op
-BenchmarkBoilUpdate/boil-8          500000	      2958 ns/op	     520 B/op	      16 allocs/op
-
-BenchmarkGORMRawBind/gorm-8    	     10000	    112577 ns/op	   38270 B/op	     595 allocs/op
-BenchmarkGORPRawBind/gorp-8    	     30000	     40967 ns/op	    8837 B/op	     312 allocs/op
-BenchmarkXORMRawBind/xorm-8    	     30000	     54739 ns/op	   12692 B/op	     273 allocs/op
-BenchmarkSQLXRawBind/sqlx-8    	    200000	     13537 ns/op	    4268 B/op	      49 allocs/op
-BenchmarkBoilRawBind/boil-8    	    200000	     11144 ns/op	    4334 B/op	      49 allocs/op
+```bash
+go test -bench . -benchmem
 ```
 
-<img style="margin-right:6px;" src="http://i.imgur.com/TglZGoI.png"/>
-<img style="margin-right:6px;" src="http://i.imgur.com/Ktm2ta4.png"/>
-<img style="margin-right:6px;" src="http://i.imgur.com/yv8kFPA.png"/>
-<img style="margin-right:6px;" src="http://i.imgur.com/890Zswe.png"/>
-<img style="margin-right:6px;" src="http://i.imgur.com/qMgoAFJ.png"/>
-<img style="margin-right:6px;" src="http://i.imgur.com/sDoNiCN.png"/>
-<img style="margin-right:6px;" src="http://i.imgur.com/EvUa4UT.png"/>
+### Results (lower is better)
+
+Test machine:
+```text
+OS:  Ubuntu 16.04
+CPU: Intel(R) Core(TM) i7-4771 CPU @ 3.50GHz
+Mem: 16GB
+Go:  go version go1.8.1 linux/amd64
+```
+
+The graphs below have many runs like this as input to calculate errors. Here
+is a sample run:
+
+```text
+BenchmarkGORMSelectAll/gorm-8         20000   66500 ns/op   28998 B/op    455 allocs/op
+BenchmarkGORPSelectAll/gorp-8         50000   31305 ns/op    9141 B/op    318 allocs/op
+BenchmarkXORMSelectAll/xorm-8         20000   66074 ns/op   16317 B/op    417 allocs/op
+BenchmarkKallaxSelectAll/kallax-8    100000   18278 ns/op    7428 B/op    145 allocs/op
+BenchmarkBoilSelectAll/boil-8        100000   12759 ns/op    3145 B/op     67 allocs/op
+
+BenchmarkGORMSelectSubset/gorm-8      20000    69469 ns/op   30008 B/op   462 allocs/op
+BenchmarkGORPSelectSubset/gorp-8      50000    31102 ns/op    9141 B/op   318 allocs/op
+BenchmarkXORMSelectSubset/xorm-8      20000    64151 ns/op   15933 B/op   414 allocs/op
+BenchmarkKallaxSelectSubset/kallax-8 100000    16996 ns/op    6499 B/op   132 allocs/op
+BenchmarkBoilSelectSubset/boil-8     100000    13579 ns/op    3281 B/op    71 allocs/op
+
+BenchmarkGORMSelectComplex/gorm-8     20000    76284 ns/op   34566 B/op   521 allocs/op
+BenchmarkGORPSelectComplex/gorp-8     50000    31886 ns/op    9501 B/op   328 allocs/op
+BenchmarkXORMSelectComplex/xorm-8     20000    68430 ns/op   17694 B/op   464 allocs/op
+BenchmarkKallaxSelectComplex/kallax-8 50000    26095 ns/op   10293 B/op   212 allocs/op
+BenchmarkBoilSelectComplex/boil-8    100000    16403 ns/op    4205 B/op   102 allocs/op
+
+BenchmarkGORMDelete/gorm-8           200000    10356 ns/op    5059 B/op    98 allocs/op
+BenchmarkGORPDelete/gorp-8          1000000     1335 ns/op     352 B/op    13 allocs/op
+BenchmarkXORMDelete/xorm-8           200000    10796 ns/op    4146 B/op   122 allocs/op
+BenchmarkKallaxDelete/kallax-8       300000     5141 ns/op    2241 B/op    48 allocs/op
+BenchmarkBoilDelete/boil-8          2000000      796 ns/op     168 B/op     8 allocs/op
+
+BenchmarkGORMInsert/gorm-8           100000    15238 ns/op    8278 B/op   150 allocs/op
+BenchmarkGORPInsert/gorp-8           300000     4648 ns/op    1616 B/op    38 allocs/op
+BenchmarkXORMInsert/xorm-8           100000    12600 ns/op    6092 B/op   138 allocs/op
+BenchmarkKallaxInsert/kallax-8       100000    15115 ns/op    6003 B/op   126 allocs/op
+BenchmarkBoilInsert/boil-8          1000000     2249 ns/op     984 B/op    23 allocs/op
+
+BenchmarkGORMUpdate/gorm-8           100000    18609 ns/op    9389 B/op   174 allocs/op
+BenchmarkGORPUpdate/gorp-8           500000     3180 ns/op    1536 B/op    35 allocs/op
+BenchmarkXORMUpdate/xorm-8           100000    13149 ns/op    5098 B/op   149 allocs/op
+BenchmarkKallaxUpdate/kallax-8       100000    22880 ns/op   11366 B/op   219 allocs/op
+BenchmarkBoilUpdate/boil-8          1000000     1810 ns/op     936 B/op    18 allocs/op
+
+BenchmarkGORMRawBind/gorm-8           20000    65821 ns/op   30502 B/op   444 allocs/op
+BenchmarkGORPRawBind/gorp-8           50000    31300 ns/op    9141 B/op   318 allocs/op
+BenchmarkXORMRawBind/xorm-8           20000    62024 ns/op   15588 B/op   403 allocs/op
+BenchmarkKallaxRawBind/kallax-8      200000     7843 ns/op    4380 B/op    46 allocs/op
+BenchmarkSQLXRawBind/sqlx-8          100000    13056 ns/op    4572 B/op    55 allocs/op
+BenchmarkBoilRawBind/boil-8          200000    11519 ns/op    4638 B/op    55 allocs/op
+```
+
+<img src="http://i.imgur.com/SltE8UQ.png"/><img src="http://i.imgur.com/lzvM5jJ.png"/><img src="http://i.imgur.com/SS0zNd2.png"/>
+
+<img src="http://i.imgur.com/Kk0IM0J.png"/><img src="http://i.imgur.com/1IFtpdP.png"/><img src="http://i.imgur.com/t6Usecx.png"/>
+
+<img src="http://i.imgur.com/98DOzcr.png"/><img src="http://i.imgur.com/NSp5r4Q.png"/><img src="http://i.imgur.com/dEGlOgI.png"/>
+
+<img src="http://i.imgur.com/W0zhuGb.png"/><img src="http://i.imgur.com/YIvDuFv.png"/><img src="http://i.imgur.com/sKwuMaU.png"/>
+
+<img src="http://i.imgur.com/ZUMYVmw.png"/><img src="http://i.imgur.com/T61rH3K.png"/><img src="http://i.imgur.com/lDr0xhY.png"/>
+
+<img src="http://i.imgur.com/LWo10M9.png"/><img src="http://i.imgur.com/Td15owT.png"/><img src="http://i.imgur.com/45XXw4K.png"/>
+
+<img src="http://i.imgur.com/lpP8qds.png"/><img src="http://i.imgur.com/hLyH3jQ.png"/><img src="http://i.imgur.com/C2v10t3.png"/>

From e4d1e606fdfd88dd07f1f9dffbf7a9defc230e5c Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Sun, 2 Apr 2017 10:00:42 -0700
Subject: [PATCH 131/179] CI for mssql

- Fix a bug where mysql was never tested in CI (hah!)
---
 circle.yml | 222 ++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 196 insertions(+), 26 deletions(-)

diff --git a/circle.yml b/circle.yml
index ed75a12..68bc895 100644
--- a/circle.yml
+++ b/circle.yml
@@ -1,28 +1,198 @@
-test:
-  pre:
-    - mkdir -p /home/ubuntu/.go_workspace/src/github.com/jstemmer
-    - go get -u github.com/jstemmer/go-junit-report
-    - echo -e "[postgres]\nhost=\"localhost\"\nport=5432\nuser=\"ubuntu\"\ndbname=\"sqlboiler\"\n[mysql]\nhost=\"localhost\"\nport=3306\nuser=\"ubuntu\"\ndbname=\"sqlboiler\"\nsslmode=\"false\"" > sqlboiler.toml
-    - createdb -U ubuntu sqlboiler
-    - psql -U ubuntu sqlboiler < ./testdata/postgres_test_schema.sql
-    - echo "create database sqlboiler;" | mysql -u ubuntu
-    - mysql -u ubuntu sqlboiler < ./testdata/mysql_test_schema.sql
-    - ./sqlboiler postgres -o "postgres"
-    - ./sqlboiler postgres -o "mysql"
-  override:
-    - go test -v -race ./... > $CIRCLE_ARTIFACTS/gotest.txt
-  post:
-    - cat $CIRCLE_ARTIFACTS/gotest.txt | go-junit-report > $CIRCLE_TEST_REPORTS/junit.xml
+version: 2
+jobs:
+  build:
+    working_directory: /root
+    docker:
+      - image: aarondl0/sqlboiler-test:latest
 
-machine:
-  environment:
-    GODIST: "go1.7.linux-amd64.tar.gz"
-  post:
-    - mkdir -p download
-    - test -e download/$GODIST || curl -o download/$GODIST https://storage.googleapis.com/golang/$GODIST
-    - sudo rm -rf /usr/local/go
-    - sudo tar -C /usr/local -xzf download/$GODIST
+      - image: postgres:9.6
+        environment:
+          POSTGRES_PASSWORD: psqlpassword
 
-dependencies:
-  cache_directories:
-    - ~/download
+      - image: mysql:5.7
+        environment:
+          MYSQL_ROOT_PASSWORD: mysqlpassword
+
+      - image: microsoft/mssql-server-linux:ctp1-4
+        environment:
+          ACCEPT_EULA: 'Y'
+          SA_PASSWORD: 'R@@tr@@t1234'
+
+    environment:
+      GOPATH: /go
+      ROOTPATH: /go/src/github.com/vattle/sqlboiler
+
+    steps:
+      - run:
+          name: Add PSQL Creds
+          command: |
+            echo "*:*:*:*:psqlpassword" > /root/.pgpass
+            chmod 600 /root/.pgpass
+      - run:
+          name: Add MySQL Creds
+          command: |
+            echo -e "[client]\nuser = root\npassword = mysqlpassword\nhost = localhost\nprotocol = tcp" > /root/.my.cnf
+            chmod 600 /root/.my.cnf
+
+      - run:
+          name: Wait for PSQL
+          command: >
+            for i in `seq 30`; do
+              echo "Waiting for psql"
+              set +o errexit
+              psql --host localhost --username postgres --dbname template1 -c 'select * from information_schema.tables;' > /dev/null
+              status=$?
+              set -o errexit
+              if [ $status -eq 0 ]; then
+                break
+              fi
+              if [ $i -eq 30 ]; then
+                echo "Failed to wait for psql"
+                exit 1
+              fi
+              sleep 1
+            done
+
+      - run:
+          name: Wait for MySQL
+          command: >
+            for i in `seq 30`; do
+              echo "Waiting for mysql"
+              set +o errexit
+              mysql --execute 'select * from information_schema.tables;' > /dev/null
+              status=$?
+              set -o errexit
+              if [ $status -eq 0 ]; then
+                break
+              fi
+              if [ $i -eq 30 ]; then
+                echo "Failed to wait for mysql"
+                exit 1
+              fi
+              sleep 1
+            done
+
+      - run:
+          name: Wait for MSSQL
+          command: >
+            for i in `seq 30`; do
+              echo "Waiting for mssql"
+              set +o errexit
+              sqlcmd -H localhost -U sa -P R@@tr@@t1234 -Q "select * from information_schema.tables;" > /dev/null
+              status=$?
+              set -o errexit
+              if [ $status -eq 0 ]; then
+                break
+              fi
+              if [ $i -eq 30 ]; then
+                echo "Failed to wait for mssql"
+                exit 1
+              fi
+              sleep 1
+            done
+
+      - run:
+          name: Make GOPATH
+          command: mkdir -p /go/src/github.com/vattle/sqlboiler
+
+      - checkout:
+          path: /go/src/github.com/vattle/sqlboiler
+
+      - run:
+          name: Create PSQL DB
+          command: |
+            createdb --host localhost --username postgres --owner postgres sqlboiler
+            psql --host localhost --username postgres --dbname sqlboiler < $ROOTPATH/testdata/postgres_test_schema.sql
+      - run:
+          name: Create MySQL DB
+          command: |
+            mysql --host localhost --execute 'create database sqlboiler;'
+            mysql --host localhost --database sqlboiler < $ROOTPATH/testdata/mysql_test_schema.sql
+      - run:
+          name: Create MSSQL DB
+          command: |
+            sqlcmd -S localhost -U sa -P R@@tr@@t1234 -Q "create database sqlboiler;"
+            sqlcmd -S localhost -U sa -P R@@tr@@t1234 -d sqlboiler -i $ROOTPATH/testdata/mssql_test_schema.sql
+
+      - run:
+          name: Build SQLBoiler
+          command: |
+            cd $ROOTPATH; go get -v
+            cd $ROOTPATH; go build -v github.com/vattle/sqlboiler
+
+      - run:
+          name: Configure SQLBoiler: PSQL
+          command: echo -e '[postgres]\nhost="localhost"\nport=5432\nuser="postgres"\ndbname="sqlboiler"\n' > $ROOTPATH/sqlboiler.toml
+      - run:
+          name: Configure SQLBoiler: MySQL
+          command: echo -e '[mysql]\nhost="localhost"\nport=3306\nuser="root"\ndbname="sqlboiler"\nsslmode="false"\n' >> $ROOTPATH/sqlboiler.toml
+      - run:
+          name: Configure SQLBoiler: MSSQL
+          command: echo -e '[mssql]\nhost="localhost"\nport=1433\nuser="sa"\npassword="R@@tr@@t1234"\ndbname="sqlboiler"\nsslmode="disable"\n' >> $ROOTPATH/sqlboiler.toml
+
+      - run:
+          name: Generate: PSQL
+          command: cd $ROOTPATH; ./sqlboiler -o postgres postgres
+      - run:
+          name: Generate: MySQL
+          command: cd $ROOTPATH; ./sqlboiler -o mysql mysql
+      - run:
+          name: Generate: MSSQL
+          command: cd $ROOTPATH; ./sqlboiler -o mssql mssql
+
+      - run:
+          name: Test
+          command: |
+            cd $ROOTPATH
+            cp ./testdata/mssql_test_schema.sql mssql/tables_schema.sql
+            mkdir -p test_results/go
+            go test -v -race ./... > test_out.txt
+            cat test_out | go-junit-report > $ROOTPATH/test_results/go/out.xml
+
+      - store_test_results:
+          path: $ROOTPATH/test_results
+#test:
+#  pre:
+#    - echo -e "[postgres]\nhost=\"localhost\"\nport=5432\nuser=\"ubuntu\"\ndbname=\"sqlboiler\"\n" > sqlboiler.toml
+#    - createdb -U ubuntu sqlboiler
+#    - psql -U ubuntu sqlboiler < ./testdata/postgres_test_schema.sql
+#
+#    - echo -e "[mysql]\nhost=\"localhost\"\nport=3306\nuser=\"ubuntu\"\ndbname=\"sqlboiler\"\nsslmode=\"false\"\n" >> sqlboiler.toml
+#    - echo "create database sqlboiler;" | mysql -u ubuntu
+#    - mysql -u ubuntu sqlboiler < ./testdata/mysql_test_schema.sql
+#
+#    - echo -e "[mssql]\nhost=\"localhost\"\nport=1433\nuser=\"sa\"\ndbname=\"sqlboiler\"\nsslmode=\"disable\"\n" >> sqlboiler.toml
+#    - docker run -e 'ACCEPT_EULA=Y' -e 'SA_PASSWORD=R@@tr@@t1234' -p 1433:1433 -d --name mssql microsoft/mssql-server-linux
+#    - sqlcmd -S localhost -U sa -P R@@tr@@t1234 -Q "create database sqlboiler;"
+#    - sqlcmd -S localhost -U sa -P R@@tr@@t1234 -d sqlboiler -i ./testdata/mssql_test_schema.sql
+#
+#    - ./sqlboiler -o postgres postgres
+#    - ./sqlboiler -o mysql    mysql
+#    - ./sqlboiler -o mssql    mssql
+#    - cp ./testdata/mssql_test_schema.sql mssql/tables_schema.sql
+#  override:
+#    - go test -v -race ./... > $CIRCLE_ARTIFACTS/gotest.txt
+#  post:
+#    - cat $CIRCLE_ARTIFACTS/gotest.txt | go-junit-report > $CIRCLE_TEST_REPORTS/junit.xml
+#
+#machine:
+#  environment:
+#    GODIST: go1.7.linux-amd64.tar.gz
+#    PATH: /home/ubuntu/.go_workspace/bin:/usr/local/go/bin:/home/ubuntu/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/opt/mssql-tools/bin
+#  post:
+#    - mkdir -p download
+#    - test -e download/$GODIST || curl -o download/$GODIST https://storage.googleapis.com/golang/$GODIST
+#    - sudo rm -rf /usr/local/go
+#    - sudo tar -C /usr/local -xzf download/$GODIST
+#
+#dependencies:
+#  pre:
+#    - mkdir -p /home/ubuntu/.go_workspace/src/github.com/jstemmer
+#    - go get -u github.com/jstemmer/go-junit-report
+#
+#    - curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
+#    - curl https://packages.microsoft.com/config/ubuntu/14.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list
+#    - sudo apt-get update; sudo apt-get install mssql-tools unixodbc-dev
+#    - docker pull microsoft/mssql-server-linux
+#  cache_directories:
+#    - ~/download

From 3a38ed1f7af36d026cd8532e10104c9568e584f0 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Sun, 23 Apr 2017 16:14:37 -0700
Subject: [PATCH 132/179] Add Dockerfile

---
 testdata/Dockerfile | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)
 create mode 100644 testdata/Dockerfile

diff --git a/testdata/Dockerfile b/testdata/Dockerfile
new file mode 100644
index 0000000..034cedc
--- /dev/null
+++ b/testdata/Dockerfile
@@ -0,0 +1,35 @@
+# This Dockerfile builds the image used for CI/testing.
+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
+
+# 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
+
+# Install database clients
+# MySQL 8.0 is still in development, so we're using 5.7 which is already
+# available in Ubuntu 16.04
+RUN curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
+    && echo 'deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main' > /etc/apt/sources.list.d/psql.list \
+    && curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - \
+    && curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list > /etc/apt/sources.list.d/msprod.list \
+    && apt-get update \
+    && env ACCEPT_EULA=Y apt-get install -y git postgresql-client-9.6 mysql-client-5.7 mssql-tools unixodbc-dev
+
+# Install Go
+RUN curl -o $GODIST https://storage.googleapis.com/golang/$GODIST \
+    && rm -rf /usr/local/go \
+    && tar -C /usr/local -xzf $GODIST
+
+RUN go get -u -v github.com/jstemmer/go-junit-report \
+    && mv /root/go/bin/go-junit-report /usr/bin/go-junit-report

From 5ee4b06c9b60caaad9633a0909c81f92a2444d03 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Sun, 23 Apr 2017 16:16:07 -0700
Subject: [PATCH 133/179] Move CircleCI file to correct spot

---
 circle.yml => .circleci/config.yml | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename circle.yml => .circleci/config.yml (100%)

diff --git a/circle.yml b/.circleci/config.yml
similarity index 100%
rename from circle.yml
rename to .circleci/config.yml

From 85c9104d3494731dcd913889f5cb5c9551f8141a Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Sun, 23 Apr 2017 16:17:46 -0700
Subject: [PATCH 134/179] Fix syntax error

---
 .circleci/config.yml | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 68bc895..e146724 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -121,27 +121,27 @@ jobs:
             cd $ROOTPATH; go build -v github.com/vattle/sqlboiler
 
       - run:
-          name: Configure SQLBoiler: PSQL
+          name: 'Configure SQLBoiler: PSQL'
           command: echo -e '[postgres]\nhost="localhost"\nport=5432\nuser="postgres"\ndbname="sqlboiler"\n' > $ROOTPATH/sqlboiler.toml
       - run:
-          name: Configure SQLBoiler: MySQL
+          name: 'Configure SQLBoiler: MySQL'
           command: echo -e '[mysql]\nhost="localhost"\nport=3306\nuser="root"\ndbname="sqlboiler"\nsslmode="false"\n' >> $ROOTPATH/sqlboiler.toml
       - run:
-          name: Configure SQLBoiler: MSSQL
+          name: 'Configure SQLBoiler: MSSQL'
           command: echo -e '[mssql]\nhost="localhost"\nport=1433\nuser="sa"\npassword="R@@tr@@t1234"\ndbname="sqlboiler"\nsslmode="disable"\n' >> $ROOTPATH/sqlboiler.toml
 
       - run:
-          name: Generate: PSQL
+          name: 'Generate: PSQL'
           command: cd $ROOTPATH; ./sqlboiler -o postgres postgres
       - run:
-          name: Generate: MySQL
+          name: 'Generate: MySQL'
           command: cd $ROOTPATH; ./sqlboiler -o mysql mysql
       - run:
-          name: Generate: MSSQL
+          name: 'Generate: MSSQL'
           command: cd $ROOTPATH; ./sqlboiler -o mssql mssql
 
       - run:
-          name: Test
+          name: Run Tests
           command: |
             cd $ROOTPATH
             cp ./testdata/mssql_test_schema.sql mssql/tables_schema.sql

From 36ae141304a916b7b2bdea2bd36f592c2c68f782 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Sun, 23 Apr 2017 16:22:10 -0700
Subject: [PATCH 135/179] Turn off PSQL SSL in tests

---
 .circleci/config.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index e146724..dcd26c2 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -122,7 +122,7 @@ jobs:
 
       - run:
           name: 'Configure SQLBoiler: PSQL'
-          command: echo -e '[postgres]\nhost="localhost"\nport=5432\nuser="postgres"\ndbname="sqlboiler"\n' > $ROOTPATH/sqlboiler.toml
+          command: echo -e '[postgres]\nhost="localhost"\nport=5432\nuser="postgres"\ndbname="sqlboiler"\nsslmode="disable"\n' > $ROOTPATH/sqlboiler.toml
       - run:
           name: 'Configure SQLBoiler: MySQL'
           command: echo -e '[mysql]\nhost="localhost"\nport=3306\nuser="root"\ndbname="sqlboiler"\nsslmode="false"\n' >> $ROOTPATH/sqlboiler.toml

From 0b44c26a264f4b38cdab07666d3fa3f897d70378 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Sun, 23 Apr 2017 16:27:32 -0700
Subject: [PATCH 136/179] Add passwords to psql/mysql

---
 .circleci/config.yml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index dcd26c2..94dc610 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -122,13 +122,13 @@ jobs:
 
       - run:
           name: 'Configure SQLBoiler: PSQL'
-          command: echo -e '[postgres]\nhost="localhost"\nport=5432\nuser="postgres"\ndbname="sqlboiler"\nsslmode="disable"\n' > $ROOTPATH/sqlboiler.toml
+          command: echo -e '[postgres]\nhost="localhost"\nport=5432\nuser="postgres"\npass="psqlpassword"\ndbname="sqlboiler"\nsslmode="disable"\n' > $ROOTPATH/sqlboiler.toml
       - run:
           name: 'Configure SQLBoiler: MySQL'
-          command: echo -e '[mysql]\nhost="localhost"\nport=3306\nuser="root"\ndbname="sqlboiler"\nsslmode="false"\n' >> $ROOTPATH/sqlboiler.toml
+          command: echo -e '[mysql]\nhost="localhost"\nport=3306\nuser="root"\npass="mysqlpassword"\ndbname="sqlboiler"\nsslmode="false"\n' >> $ROOTPATH/sqlboiler.toml
       - run:
           name: 'Configure SQLBoiler: MSSQL'
-          command: echo -e '[mssql]\nhost="localhost"\nport=1433\nuser="sa"\npassword="R@@tr@@t1234"\ndbname="sqlboiler"\nsslmode="disable"\n' >> $ROOTPATH/sqlboiler.toml
+          command: echo -e '[mssql]\nhost="localhost"\nport=1433\nuser="sa"\npass="R@@tr@@t1234"\ndbname="sqlboiler"\nsslmode="disable"\n' >> $ROOTPATH/sqlboiler.toml
 
       - run:
           name: 'Generate: PSQL'

From 7de817b111412e574cd1ac8b1bf13a49cc4a56da Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Sun, 23 Apr 2017 16:43:41 -0700
Subject: [PATCH 137/179] Add dep fetch to tests part

---
 .circleci/config.yml | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 94dc610..d233e6a 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -117,7 +117,7 @@ jobs:
       - run:
           name: Build SQLBoiler
           command: |
-            cd $ROOTPATH; go get -v
+            cd $ROOTPATH; go get -v -t
             cd $ROOTPATH; go build -v github.com/vattle/sqlboiler
 
       - run:
@@ -140,17 +140,27 @@ jobs:
           name: 'Generate: MSSQL'
           command: cd $ROOTPATH; ./sqlboiler -o mssql mssql
 
+      - run:
+          name: Download generated and test deps
+          command: |
+            cd $ROOTPATH
+            go get -v -t ./...
+
       - run:
           name: Run Tests
           command: |
             cd $ROOTPATH
             cp ./testdata/mssql_test_schema.sql mssql/tables_schema.sql
-            mkdir -p test_results/go
-            go test -v -race ./... > test_out.txt
-            cat test_out | go-junit-report > $ROOTPATH/test_results/go/out.xml
+            go test -v -race ./... | tee test_out.txt
+
+      - run:
+          name: Convert test output to JUNIT
+          command: |
+            mkdir -p $HOME/test_results/go
+            cat $ROOTPATH/test_out.txt | go-junit-report > $HOME/test_results/go/out.xml
 
       - store_test_results:
-          path: $ROOTPATH/test_results
+          path: test_results
 #test:
 #  pre:
 #    - echo -e "[postgres]\nhost=\"localhost\"\nport=5432\nuser=\"ubuntu\"\ndbname=\"sqlboiler\"\n" > sqlboiler.toml

From bdd28d9d5b9b48bbb3c538dfcf4d1043a76ac240 Mon Sep 17 00:00:00 2001
From: Maksim <maksim.levental@gmail.com>
Date: Mon, 24 Apr 2017 12:46:56 -0400
Subject: [PATCH 138/179] fix removing whitespace

---
 templates/16_update.tpl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index 708723e..50c7f49 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -56,7 +56,7 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 		{{if eq .DriverName "mssql"}}
 		wl = strmangle.SetComplement(wl, {{$varNameSingular}}ColumnsWithAuto)
 		{{end}}
-		{{- if not .NoAutoTimestamps}}
+		{{if not .NoAutoTimestamps}}
 		if len(whitelist) == 0 {
 			wl = strmangle.SetComplement(wl, []string{"created_at"})
 		}

From a3442a5ab499510227f9b4cea5d5280c6227569a Mon Sep 17 00:00:00 2001
From: Sergey Kurt <sergeykurt@outlook.com>
Date: Fri, 28 Apr 2017 23:58:17 +0300
Subject: [PATCH 139/179] Fixed INSERT-SELECT deadlocks in tests

---
 templates_test/main_test/mssql_main.tpl | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/templates_test/main_test/mssql_main.tpl b/templates_test/main_test/mssql_main.tpl
index c1c76f2..ba46be7 100644
--- a/templates_test/main_test/mssql_main.tpl
+++ b/templates_test/main_test/mssql_main.tpl
@@ -68,6 +68,9 @@ func (m *mssqlTester) sslMode(mode string) string {
 func (m *mssqlTester) createTestDB() error {
 	sql := fmt.Sprintf(`
 	CREATE DATABASE %s;
+	GO
+	ALTER DATABASE %[1]s
+	SET READ_COMMITTED_SNAPSHOT ON;
 	GO`, m.testDBName)
 	return m.runCmd(sql, "sqlcmd", "-S", m.host, "-U", m.user, "-P", m.pass)
 }

From ecad5334fbcd1f8e3ebcc686efa91250380af0de Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Fri, 28 Apr 2017 20:01:27 -0700
Subject: [PATCH 140/179] Fix MySQL protocol selection

- If MySQL host exists on the filesystem as a file, then expect that
  this is actually a unix socket. If not, add protocol=tcp to force the
  mysql client to use tcp otherwise it tries unix sockets for no reason.
  Thanks MySQL.
---
 templates_test/main_test/mysql_main.tpl | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/templates_test/main_test/mysql_main.tpl b/templates_test/main_test/mysql_main.tpl
index fc43d3d..b95b32c 100644
--- a/templates_test/main_test/mysql_main.tpl
+++ b/templates_test/main_test/mysql_main.tpl
@@ -90,12 +90,23 @@ func (m *mysqlTester) makeOptionFile() error {
 		return errors.Wrap(err, "failed to create option file")
 	}
 
+	isTCP := false
+	_, err = os.Stat(m.host)
+	if os.IsNotExist(err) {
+		isTCP = true
+	} else if err != nil {
+		return errors.Wrap(err, "could not stat m.host")
+	}
+
 	fmt.Fprintln(tmp, "[client]")
 	fmt.Fprintf(tmp, "host=%s\n", m.host)
 	fmt.Fprintf(tmp, "port=%d\n", m.port)
 	fmt.Fprintf(tmp, "user=%s\n", m.user)
 	fmt.Fprintf(tmp, "password=%s\n", m.pass)
 	fmt.Fprintf(tmp, "ssl-mode=%s\n", m.sslMode(m.sslmode))
+	if isTCP {
+		fmt.Fprintln(tmp, "protocol=tcp")
+	}
 
 	fmt.Fprintln(tmp, "[mysqldump]")
 	fmt.Fprintf(tmp, "host=%s\n", m.host)
@@ -103,6 +114,9 @@ func (m *mysqlTester) makeOptionFile() error {
 	fmt.Fprintf(tmp, "user=%s\n", m.user)
 	fmt.Fprintf(tmp, "password=%s\n", m.pass)
 	fmt.Fprintf(tmp, "ssl-mode=%s\n", m.sslMode(m.sslmode))
+	if isTCP {
+		fmt.Fprintln(tmp, "protocol=tcp")
+	}
 
 	m.optionFile = tmp.Name()
 

From 112a836af2f9ab171e47a312292b0b06f52599f0 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Fri, 28 Apr 2017 21:07:39 -0700
Subject: [PATCH 141/179] Make UDT's that aren't enums fall through

- This allows typse that are not enumerations to properly escape the
  enumeration code in the query.
- Fix #131
---
 bdb/drivers/postgres.go | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/bdb/drivers/postgres.go b/bdb/drivers/postgres.go
index ec1aede..34cdd78 100644
--- a/bdb/drivers/postgres.go
+++ b/bdb/drivers/postgres.go
@@ -3,6 +3,7 @@ package drivers
 import (
 	"database/sql"
 	"fmt"
+	"os"
 	"strings"
 
 	// Side-effect import sql driver
@@ -132,7 +133,7 @@ func (p *PostgresDriver) Columns(schema, tableName string) ([]bdb.Column, error)
 		select
 		c.column_name,
 		(
-			case when c.data_type = 'USER-DEFINED' and c.udt_name <> 'hstore'
+			case when pgt.typtype = 'e'
 			then
 			(
 				select 'enum.' || c.udt_name || '(''' || string_agg(labels.label, ''',''') || ''')'
@@ -176,6 +177,8 @@ func (p *PostgresDriver) Columns(schema, tableName string) ([]bdb.Column, error)
 		)) as is_unique
 
 		from information_schema.columns as c
+		inner join pg_namespace as pgn on pgn.nspname = c.udt_schema
+		left join pg_type pgt on c.data_type = 'USER-DEFINED' and pgn.oid = pgt.typnamespace and c.udt_name = pgt.typname
 		left join information_schema.element_types e
 			on ((c.table_catalog, c.table_schema, c.table_name, 'TABLE', c.dtd_identifier)
 			= (e.object_catalog, e.object_schema, e.object_name, e.object_type, e.collection_type_identifier))
@@ -349,7 +352,7 @@ func (p *PostgresDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 				c.DBType = "hstore"
 			} else {
 				c.Type = "string"
-				fmt.Printf("Warning: Incompatible data type detected: %s\n", c.UDTName)
+				fmt.Fprintln(os.Stderr, "Warning: Incompatible data type detected: %s\n", c.UDTName)
 			}
 		default:
 			c.Type = "null.String"

From 3b5ab423b3028967f3bbf289d60bd164347ecaf0 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Mon, 1 May 2017 18:41:49 -0700
Subject: [PATCH 142/179] Bump version

---
 main.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/main.go b/main.go
index acc7b1e..793055d 100644
--- a/main.go
+++ b/main.go
@@ -14,7 +14,7 @@ import (
 	"github.com/vattle/sqlboiler/boilingcore"
 )
 
-const sqlBoilerVersion = "2.2.0"
+const sqlBoilerVersion = "2.3.0"
 
 var (
 	cmdState  *boilingcore.State

From 070df18197de03cdc57b0b60e106e8d817f8ecc7 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Mon, 1 May 2017 19:44:52 -0700
Subject: [PATCH 143/179] Add mailing lists

---
 README.md | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/README.md b/README.md
index a0a78fd..194fdd8 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,8 @@
 
 [![License](https://img.shields.io/badge/license-BSD-blue.svg)](https://github.com/vattle/sqlboiler/blob/master/LICENSE)
 [![GoDoc](https://godoc.org/github.com/vattle/sqlboiler?status.svg)](https://godoc.org/github.com/vattle/sqlboiler)
+[![Mail](https://img.shields.io/badge/mail%20list-sqlboiler-lightgrey.svg)](https://groups.google.com/a/volatile.tech/forum/#!forum/sqlboiler)
+[![Mail-Annc](https://img.shields.io/badge/mail%20list-sqlboiler--announce-lightgrey.svg)](https://groups.google.com/a/volatile.tech/forum/#!forum/sqlboiler-announce)
 [![Slack](https://img.shields.io/badge/slack-%23general-lightgrey.svg)](https://sqlboiler.from-the.cloud)
 [![CircleCI](https://circleci.com/gh/vattle/sqlboiler.svg?style=shield)](https://circleci.com/gh/vattle/sqlboiler)
 [![Go Report Card](https://goreportcard.com/badge/vattle/sqlboiler)](http://goreportcard.com/report/vattle/sqlboiler)

From 1467b88f04e176c5fadf5fc9878f57f9a0cfccba Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Mon, 8 May 2017 13:10:21 -0400
Subject: [PATCH 144/179] detect unsigned int columns in mysql

---
 bdb/drivers/mysql.go | 53 +++++++++++++++++++++++++++++++++++++-------
 1 file changed, 45 insertions(+), 8 deletions(-)

diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go
index ea24f1b..346e473 100644
--- a/bdb/drivers/mysql.go
+++ b/bdb/drivers/mysql.go
@@ -272,23 +272,42 @@ func (m *MySQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey
 // "varchar" to "string" and "bigint" to "int64". It returns this parsed data
 // as a Column object.
 func (m *MySQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
+	unsigned := strings.Contains(c.FullDBType, "unsigned")
 	if c.Nullable {
 		switch c.DBType {
 		case "tinyint":
 			// map tinyint(1) to bool if TinyintAsBool is true
 			if TinyintAsBool && c.FullDBType == "tinyint(1)" {
 				c.Type = "null.Bool"
+			} else if unsigned {
+				c.Type = "null.Uint8"
 			} else {
 				c.Type = "null.Int8"
 			}
 		case "smallint":
-			c.Type = "null.Int16"
+			if unsigned {
+				c.Type = "null.Uint16"
+			} else {
+				c.Type = "null.Int16"
+			}
 		case "mediumint":
-			c.Type = "null.Int32"
+			if unsigned {
+				c.Type = "null.Uint32"
+			} else {
+				c.Type = "null.Int32"
+			}
 		case "int", "integer":
-			c.Type = "null.Int"
+			if unsigned {
+				c.Type = "null.Uint"
+			} else {
+				c.Type = "null.Int"
+			}
 		case "bigint":
-			c.Type = "null.Int64"
+			if unsigned {
+				c.Type = "null.Uint64"
+			} else {
+				c.Type = "null.Uint64"
+			}
 		case "float":
 			c.Type = "null.Float32"
 		case "double", "double precision", "real":
@@ -310,17 +329,35 @@ func (m *MySQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			// map tinyint(1) to bool if TinyintAsBool is true
 			if TinyintAsBool && c.FullDBType == "tinyint(1)" {
 				c.Type = "bool"
+			} else if unsigned {
+				c.Type = "uint8"
 			} else {
 				c.Type = "int8"
 			}
 		case "smallint":
-			c.Type = "int16"
+			if unsigned {
+				c.Type = "uint16"
+			} else {
+				c.Type = "int16"
+			}
 		case "mediumint":
-			c.Type = "int32"
+			if unsigned {
+				c.Type = "uint32"
+			} else {
+				c.Type = "int32"
+			}
 		case "int", "integer":
-			c.Type = "int"
+			if unsigned {
+				c.Type = "uint"
+			} else {
+				c.Type = "int"
+			}
 		case "bigint":
-			c.Type = "int64"
+			if unsigned {
+				c.Type = "uint64"
+			} else {
+				c.Type = "int64"
+			}
 		case "float":
 			c.Type = "float32"
 		case "double", "double precision", "real":

From 451723ccb9b1535c98a69b3cdb10f2cf64c9f460 Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Mon, 8 May 2017 13:25:15 -0400
Subject: [PATCH 145/179] fix imports to point at lbryio repo

---
 bdb/column.go                    |  2 +-
 bdb/drivers/mock.go              |  4 +--
 bdb/drivers/mssql.go             |  2 +-
 bdb/drivers/mysql.go             |  2 +-
 bdb/drivers/postgres.go          |  4 +--
 bdb/interface_test.go            |  2 +-
 boilingcore/boilingcore.go       | 10 +++---
 boilingcore/imports.go           | 54 ++++++++++++++++----------------
 boilingcore/imports_test.go      | 16 +++++-----
 boilingcore/output.go            |  2 +-
 boilingcore/templates.go         |  6 ++--
 boilingcore/text_helpers.go      |  4 +--
 boilingcore/text_helpers_test.go |  4 +--
 main.go                          |  6 ++--
 queries/eager_load.go            |  4 +--
 queries/eager_load_test.go       |  2 +-
 queries/helpers.go               |  2 +-
 queries/qm/query_mods.go         |  2 +-
 queries/query.go                 |  2 +-
 queries/query_builders.go        |  2 +-
 queries/reflect.go               |  4 +--
 randomize/randomize.go           |  4 +--
 22 files changed, 70 insertions(+), 70 deletions(-)

diff --git a/bdb/column.go b/bdb/column.go
index a3632fc..da56e48 100644
--- a/bdb/column.go
+++ b/bdb/column.go
@@ -3,7 +3,7 @@ package bdb
 import (
 	"strings"
 
-	"github.com/vattle/sqlboiler/strmangle"
+	"github.com/lbryio/sqlboiler/strmangle"
 )
 
 // Column holds information about a database column.
diff --git a/bdb/drivers/mock.go b/bdb/drivers/mock.go
index 1c91d0e..7d14f2a 100644
--- a/bdb/drivers/mock.go
+++ b/bdb/drivers/mock.go
@@ -1,8 +1,8 @@
 package drivers
 
 import (
-	"github.com/vattle/sqlboiler/bdb"
-	"github.com/vattle/sqlboiler/strmangle"
+	"github.com/lbryio/sqlboiler/bdb"
+	"github.com/lbryio/sqlboiler/strmangle"
 )
 
 // MockDriver is a mock implementation of the bdb driver Interface
diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index cb3290a..e59330b 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -8,7 +8,7 @@ import (
 
 	_ "github.com/denisenkom/go-mssqldb"
 	"github.com/pkg/errors"
-	"github.com/vattle/sqlboiler/bdb"
+	"github.com/lbryio/sqlboiler/bdb"
 )
 
 // MSSQLDriver holds the database connection string and a handle
diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go
index 346e473..bb73574 100644
--- a/bdb/drivers/mysql.go
+++ b/bdb/drivers/mysql.go
@@ -8,7 +8,7 @@ import (
 
 	"github.com/go-sql-driver/mysql"
 	"github.com/pkg/errors"
-	"github.com/vattle/sqlboiler/bdb"
+	"github.com/lbryio/sqlboiler/bdb"
 )
 
 // TinyintAsBool is a global that is set from main.go if a user specifies
diff --git a/bdb/drivers/postgres.go b/bdb/drivers/postgres.go
index 34cdd78..ad73a2e 100644
--- a/bdb/drivers/postgres.go
+++ b/bdb/drivers/postgres.go
@@ -10,8 +10,8 @@ import (
 
 	_ "github.com/lib/pq"
 	"github.com/pkg/errors"
-	"github.com/vattle/sqlboiler/bdb"
-	"github.com/vattle/sqlboiler/strmangle"
+	"github.com/lbryio/sqlboiler/bdb"
+	"github.com/lbryio/sqlboiler/strmangle"
 )
 
 // PostgresDriver holds the database connection string and a handle
diff --git a/bdb/interface_test.go b/bdb/interface_test.go
index 4d429c6..e5d28fb 100644
--- a/bdb/interface_test.go
+++ b/bdb/interface_test.go
@@ -3,7 +3,7 @@ package bdb
 import (
 	"testing"
 
-	"github.com/vattle/sqlboiler/strmangle"
+	"github.com/lbryio/sqlboiler/strmangle"
 )
 
 type testMockDriver struct{}
diff --git a/boilingcore/boilingcore.go b/boilingcore/boilingcore.go
index 5e00687..e667cae 100644
--- a/boilingcore/boilingcore.go
+++ b/boilingcore/boilingcore.go
@@ -13,10 +13,10 @@ import (
 	"text/template"
 
 	"github.com/pkg/errors"
-	"github.com/vattle/sqlboiler/bdb"
-	"github.com/vattle/sqlboiler/bdb/drivers"
-	"github.com/vattle/sqlboiler/queries"
-	"github.com/vattle/sqlboiler/strmangle"
+	"github.com/lbryio/sqlboiler/bdb"
+	"github.com/lbryio/sqlboiler/bdb/drivers"
+	"github.com/lbryio/sqlboiler/queries"
+	"github.com/lbryio/sqlboiler/strmangle"
 )
 
 const (
@@ -267,7 +267,7 @@ func (s *State) processReplacements() error {
 	return nil
 }
 
-var basePackage = "github.com/vattle/sqlboiler"
+var basePackage = "github.com/lbryio/sqlboiler"
 
 func getBasePath(baseDirConfig string) (string, error) {
 	if len(baseDirConfig) > 0 {
diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index eafcf28..1fbca14 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -6,7 +6,7 @@ import (
 	"sort"
 	"strings"
 
-	"github.com/vattle/sqlboiler/bdb"
+	"github.com/lbryio/sqlboiler/bdb"
 )
 
 // imports defines the optional standard imports and
@@ -171,25 +171,25 @@ func newImporter() importer {
 		},
 		thirdParty: importList{
 			`"github.com/pkg/errors"`,
-			`"github.com/vattle/sqlboiler/boil"`,
-			`"github.com/vattle/sqlboiler/queries"`,
-			`"github.com/vattle/sqlboiler/queries/qm"`,
-			`"github.com/vattle/sqlboiler/strmangle"`,
+			`"github.com/lbryio/sqlboiler/boil"`,
+			`"github.com/lbryio/sqlboiler/queries"`,
+			`"github.com/lbryio/sqlboiler/queries/qm"`,
+			`"github.com/lbryio/sqlboiler/strmangle"`,
 		},
 	}
 
 	imp.Singleton = mapImports{
 		"boil_queries": {
 			thirdParty: importList{
-				`"github.com/vattle/sqlboiler/boil"`,
-				`"github.com/vattle/sqlboiler/queries"`,
-				`"github.com/vattle/sqlboiler/queries/qm"`,
+				`"github.com/lbryio/sqlboiler/boil"`,
+				`"github.com/lbryio/sqlboiler/queries"`,
+				`"github.com/lbryio/sqlboiler/queries/qm"`,
 			},
 		},
 		"boil_types": {
 			thirdParty: importList{
 				`"github.com/pkg/errors"`,
-				`"github.com/vattle/sqlboiler/strmangle"`,
+				`"github.com/lbryio/sqlboiler/strmangle"`,
 			},
 		},
 	}
@@ -201,9 +201,9 @@ func newImporter() importer {
 			`"testing"`,
 		},
 		thirdParty: importList{
-			`"github.com/vattle/sqlboiler/boil"`,
-			`"github.com/vattle/sqlboiler/randomize"`,
-			`"github.com/vattle/sqlboiler/strmangle"`,
+			`"github.com/lbryio/sqlboiler/boil"`,
+			`"github.com/lbryio/sqlboiler/randomize"`,
+			`"github.com/lbryio/sqlboiler/strmangle"`,
 		},
 	}
 
@@ -223,7 +223,7 @@ func newImporter() importer {
 				`"github.com/kat-co/vala"`,
 				`"github.com/pkg/errors"`,
 				`"github.com/spf13/viper"`,
-				`"github.com/vattle/sqlboiler/boil"`,
+				`"github.com/lbryio/sqlboiler/boil"`,
 			},
 		},
 		"boil_queries_test": {
@@ -236,7 +236,7 @@ func newImporter() importer {
 				`"regexp"`,
 			},
 			thirdParty: importList{
-				`"github.com/vattle/sqlboiler/boil"`,
+				`"github.com/lbryio/sqlboiler/boil"`,
 			},
 		},
 		"boil_suites_test": {
@@ -261,8 +261,8 @@ func newImporter() importer {
 			thirdParty: importList{
 				`"github.com/pkg/errors"`,
 				`"github.com/spf13/viper"`,
-				`"github.com/vattle/sqlboiler/bdb/drivers"`,
-				`"github.com/vattle/sqlboiler/randomize"`,
+				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
+				`"github.com/lbryio/sqlboiler/randomize"`,
 				`_ "github.com/lib/pq"`,
 			},
 		},
@@ -280,8 +280,8 @@ func newImporter() importer {
 			thirdParty: importList{
 				`"github.com/pkg/errors"`,
 				`"github.com/spf13/viper"`,
-				`"github.com/vattle/sqlboiler/bdb/drivers"`,
-				`"github.com/vattle/sqlboiler/randomize"`,
+				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
+				`"github.com/lbryio/sqlboiler/randomize"`,
 				`_ "github.com/go-sql-driver/mysql"`,
 			},
 		},
@@ -297,8 +297,8 @@ func newImporter() importer {
 			thirdParty: importList{
 				`"github.com/pkg/errors"`,
 				`"github.com/spf13/viper"`,
-				`"github.com/vattle/sqlboiler/bdb/drivers"`,
-				`"github.com/vattle/sqlboiler/randomize"`,
+				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
+				`"github.com/lbryio/sqlboiler/randomize"`,
 				`_ "github.com/denisenkom/go-mssqldb"`,
 			},
 		},
@@ -363,25 +363,25 @@ func newImporter() importer {
 			standard: importList{`"time"`},
 		},
 		"types.JSON": {
-			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+			thirdParty: importList{`"github.com/lbryio/sqlboiler/types"`},
 		},
 		"types.BytesArray": {
-			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+			thirdParty: importList{`"github.com/lbryio/sqlboiler/types"`},
 		},
 		"types.Int64Array": {
-			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+			thirdParty: importList{`"github.com/lbryio/sqlboiler/types"`},
 		},
 		"types.Float64Array": {
-			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+			thirdParty: importList{`"github.com/lbryio/sqlboiler/types"`},
 		},
 		"types.BoolArray": {
-			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+			thirdParty: importList{`"github.com/lbryio/sqlboiler/types"`},
 		},
 		"types.StringArray": {
-			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+			thirdParty: importList{`"github.com/lbryio/sqlboiler/types"`},
 		},
 		"types.Hstore": {
-			thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
+			thirdParty: importList{`"github.com/lbryio/sqlboiler/types"`},
 		},
 	}
 
diff --git a/boilingcore/imports_test.go b/boilingcore/imports_test.go
index 6f2cde4..ff2362d 100644
--- a/boilingcore/imports_test.go
+++ b/boilingcore/imports_test.go
@@ -6,7 +6,7 @@ import (
 	"testing"
 
 	"github.com/pkg/errors"
-	"github.com/vattle/sqlboiler/bdb"
+	"github.com/lbryio/sqlboiler/bdb"
 )
 
 func TestImportsSort(t *testing.T) {
@@ -234,7 +234,7 @@ func TestCombineTypeImports(t *testing.T) {
 			`"fmt"`,
 		},
 		thirdParty: importList{
-			`"github.com/vattle/sqlboiler/boil"`,
+			`"github.com/lbryio/sqlboiler/boil"`,
 		},
 	}
 
@@ -245,7 +245,7 @@ func TestCombineTypeImports(t *testing.T) {
 			`"time"`,
 		},
 		thirdParty: importList{
-			`"github.com/vattle/sqlboiler/boil"`,
+			`"github.com/lbryio/sqlboiler/boil"`,
 			`"gopkg.in/nullbio/null.v6"`,
 		},
 	}
@@ -280,7 +280,7 @@ func TestCombineTypeImports(t *testing.T) {
 			`"time"`,
 		},
 		thirdParty: importList{
-			`"github.com/vattle/sqlboiler/boil"`,
+			`"github.com/lbryio/sqlboiler/boil"`,
 			`"gopkg.in/nullbio/null.v6"`,
 		},
 	}
@@ -297,11 +297,11 @@ func TestCombineImports(t *testing.T) {
 
 	a := imports{
 		standard:   importList{"fmt"},
-		thirdParty: importList{"github.com/vattle/sqlboiler", "gopkg.in/nullbio/null.v6"},
+		thirdParty: importList{"github.com/lbryio/sqlboiler", "gopkg.in/nullbio/null.v6"},
 	}
 	b := imports{
 		standard:   importList{"os"},
-		thirdParty: importList{"github.com/vattle/sqlboiler"},
+		thirdParty: importList{"github.com/lbryio/sqlboiler"},
 	}
 
 	c := combineImports(a, b)
@@ -309,8 +309,8 @@ func TestCombineImports(t *testing.T) {
 	if c.standard[0] != "fmt" && c.standard[1] != "os" {
 		t.Errorf("Wanted: fmt, os got: %#v", c.standard)
 	}
-	if c.thirdParty[0] != "github.com/vattle/sqlboiler" && c.thirdParty[1] != "gopkg.in/nullbio/null.v6" {
-		t.Errorf("Wanted: github.com/vattle/sqlboiler, gopkg.in/nullbio/null.v6 got: %#v", c.thirdParty)
+	if c.thirdParty[0] != "github.com/lbryio/sqlboiler" && c.thirdParty[1] != "gopkg.in/nullbio/null.v6" {
+		t.Errorf("Wanted: github.com/lbryio/sqlboiler, gopkg.in/nullbio/null.v6 got: %#v", c.thirdParty)
 	}
 }
 
diff --git a/boilingcore/output.go b/boilingcore/output.go
index 64f28b5..5c65634 100644
--- a/boilingcore/output.go
+++ b/boilingcore/output.go
@@ -14,7 +14,7 @@ import (
 	"github.com/pkg/errors"
 )
 
-var noEditDisclaimer = []byte(`// This file is generated by SQLBoiler (https://github.com/vattle/sqlboiler)
+var noEditDisclaimer = []byte(`// This file is generated by SQLBoiler (https://github.com/lbryio/sqlboiler)
 // and is meant to be re-generated in place and/or deleted at any time.
 // DO NOT EDIT
 
diff --git a/boilingcore/templates.go b/boilingcore/templates.go
index 9c60739..62c0ae5 100644
--- a/boilingcore/templates.go
+++ b/boilingcore/templates.go
@@ -9,9 +9,9 @@ import (
 	"text/template"
 
 	"github.com/pkg/errors"
-	"github.com/vattle/sqlboiler/bdb"
-	"github.com/vattle/sqlboiler/queries"
-	"github.com/vattle/sqlboiler/strmangle"
+	"github.com/lbryio/sqlboiler/bdb"
+	"github.com/lbryio/sqlboiler/queries"
+	"github.com/lbryio/sqlboiler/strmangle"
 )
 
 // templateData for sqlboiler templates
diff --git a/boilingcore/text_helpers.go b/boilingcore/text_helpers.go
index e9577a7..0bce73f 100644
--- a/boilingcore/text_helpers.go
+++ b/boilingcore/text_helpers.go
@@ -4,8 +4,8 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/vattle/sqlboiler/bdb"
-	"github.com/vattle/sqlboiler/strmangle"
+	"github.com/lbryio/sqlboiler/bdb"
+	"github.com/lbryio/sqlboiler/strmangle"
 )
 
 // TxtToOne contains text that will be used by templates for a one-to-many or
diff --git a/boilingcore/text_helpers_test.go b/boilingcore/text_helpers_test.go
index 8beed50..835ed0d 100644
--- a/boilingcore/text_helpers_test.go
+++ b/boilingcore/text_helpers_test.go
@@ -5,8 +5,8 @@ import (
 	"testing"
 
 	"github.com/davecgh/go-spew/spew"
-	"github.com/vattle/sqlboiler/bdb"
-	"github.com/vattle/sqlboiler/bdb/drivers"
+	"github.com/lbryio/sqlboiler/bdb"
+	"github.com/lbryio/sqlboiler/bdb/drivers"
 )
 
 func TestTxtsFromOne(t *testing.T) {
diff --git a/main.go b/main.go
index 793055d..5103116 100644
--- a/main.go
+++ b/main.go
@@ -10,8 +10,8 @@ import (
 	"github.com/kat-co/vala"
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
-	"github.com/vattle/sqlboiler/bdb/drivers"
-	"github.com/vattle/sqlboiler/boilingcore"
+	"github.com/lbryio/sqlboiler/bdb/drivers"
+	"github.com/lbryio/sqlboiler/boilingcore"
 )
 
 const sqlBoilerVersion = "2.3.0"
@@ -62,7 +62,7 @@ func main() {
 		Use:   "sqlboiler [flags] <driver>",
 		Short: "SQL Boiler generates an ORM tailored to your database schema.",
 		Long: "SQL Boiler generates a Go ORM from template files, tailored to your database schema.\n" +
-			`Complete documentation is available at http://github.com/vattle/sqlboiler`,
+			`Complete documentation is available at http://github.com/lbryio/sqlboiler`,
 		Example:       `sqlboiler postgres`,
 		PreRunE:       preRun,
 		RunE:          run,
diff --git a/queries/eager_load.go b/queries/eager_load.go
index 18abcc8..081aac4 100644
--- a/queries/eager_load.go
+++ b/queries/eager_load.go
@@ -6,8 +6,8 @@ import (
 	"strings"
 
 	"github.com/pkg/errors"
-	"github.com/vattle/sqlboiler/boil"
-	"github.com/vattle/sqlboiler/strmangle"
+	"github.com/lbryio/sqlboiler/boil"
+	"github.com/lbryio/sqlboiler/strmangle"
 )
 
 type loadRelationshipState struct {
diff --git a/queries/eager_load_test.go b/queries/eager_load_test.go
index dc3f5f1..c7b3cef 100644
--- a/queries/eager_load_test.go
+++ b/queries/eager_load_test.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"testing"
 
-	"github.com/vattle/sqlboiler/boil"
+	"github.com/lbryio/sqlboiler/boil"
 )
 
 var testEagerCounters struct {
diff --git a/queries/helpers.go b/queries/helpers.go
index 59ad8a3..b953a67 100644
--- a/queries/helpers.go
+++ b/queries/helpers.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"reflect"
 
-	"github.com/vattle/sqlboiler/strmangle"
+	"github.com/lbryio/sqlboiler/strmangle"
 )
 
 // NonZeroDefaultSet returns the fields included in the
diff --git a/queries/qm/query_mods.go b/queries/qm/query_mods.go
index 81ae3a0..89d31d4 100644
--- a/queries/qm/query_mods.go
+++ b/queries/qm/query_mods.go
@@ -1,6 +1,6 @@
 package qm
 
-import "github.com/vattle/sqlboiler/queries"
+import "github.com/lbryio/sqlboiler/queries"
 
 // QueryMod to modify the query object
 type QueryMod func(q *queries.Query)
diff --git a/queries/query.go b/queries/query.go
index 8c2abdb..be539e5 100644
--- a/queries/query.go
+++ b/queries/query.go
@@ -4,7 +4,7 @@ import (
 	"database/sql"
 	"fmt"
 
-	"github.com/vattle/sqlboiler/boil"
+	"github.com/lbryio/sqlboiler/boil"
 )
 
 // joinKind is the type of join
diff --git a/queries/query_builders.go b/queries/query_builders.go
index 2188044..d221aca 100644
--- a/queries/query_builders.go
+++ b/queries/query_builders.go
@@ -7,7 +7,7 @@ import (
 	"sort"
 	"strings"
 
-	"github.com/vattle/sqlboiler/strmangle"
+	"github.com/lbryio/sqlboiler/strmangle"
 )
 
 var (
diff --git a/queries/reflect.go b/queries/reflect.go
index 9c55b33..8cf8f3d 100644
--- a/queries/reflect.go
+++ b/queries/reflect.go
@@ -8,8 +8,8 @@ import (
 	"sync"
 
 	"github.com/pkg/errors"
-	"github.com/vattle/sqlboiler/boil"
-	"github.com/vattle/sqlboiler/strmangle"
+	"github.com/lbryio/sqlboiler/boil"
+	"github.com/lbryio/sqlboiler/strmangle"
 )
 
 var (
diff --git a/randomize/randomize.go b/randomize/randomize.go
index 59f7eff..ea99c43 100644
--- a/randomize/randomize.go
+++ b/randomize/randomize.go
@@ -18,8 +18,8 @@ import (
 
 	"github.com/pkg/errors"
 	"github.com/satori/go.uuid"
-	"github.com/vattle/sqlboiler/strmangle"
-	"github.com/vattle/sqlboiler/types"
+	"github.com/lbryio/sqlboiler/strmangle"
+	"github.com/lbryio/sqlboiler/types"
 )
 
 var (

From f863ecb48e3215e98d75dfebeefbd38061cad936 Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Mon, 8 May 2017 16:30:40 -0400
Subject: [PATCH 146/179] add model Filters, FindOrCreate methods, IsNew()

---
 templates/00_struct.tpl |  7 ++++
 templates/14_find.tpl   | 79 +++++++++++++++++++++++++++++++++++++++++
 templates/20_exists.tpl | 36 +++++++++++++++++++
 3 files changed, 122 insertions(+)

diff --git a/templates/00_struct.tpl b/templates/00_struct.tpl
index 585feee..f9c3a04 100644
--- a/templates/00_struct.tpl
+++ b/templates/00_struct.tpl
@@ -17,6 +17,13 @@ type {{$modelName}} struct {
 	{{end -}}
 }
 
+// {{$modelName}}Filter allows you to filter on any columns by making them all pointers.
+type {{$modelName}}Filter struct {
+	{{range $column := .Table.Columns -}}
+	{{titleCase $column.Name}} *{{$column.Type}} `{{generateTags $dot.Tags $column.Name}}boil:"{{$column.Name}}" json:"{{$column.Name}},omitempty" toml:"{{$column.Name}}" yaml:"{{$column.Name}},omitempty"`
+	{{end -}}
+}
+
 {{- if .Table.IsJoinTable -}}
 {{- else}}
 // {{$modelNameCamel}}R is where relationships are stored.
diff --git a/templates/14_find.tpl b/templates/14_find.tpl
index 097f184..12ffa85 100644
--- a/templates/14_find.tpl
+++ b/templates/14_find.tpl
@@ -53,3 +53,82 @@ func Find{{$tableNameSingular}}P(exec boil.Executor, {{$pkArgs}}, selectCols ...
 
 	return retobj
 }
+
+// FindOne{{$tableNameSingular}} retrieves a single record using filters.
+func FindOne{{$tableNameSingular}}(exec boil.Executor, filters {{$tableNameSingular}}Filter) (*{{$tableNameSingular}}, error) {
+	{{$varNameSingular}}Obj := &{{$tableNameSingular}}{}
+
+	query := NewQuery(exec, qm.Select("*"), qm.From("{{.Table.Name | .SchemaTable}}"))
+
+	r := reflect.ValueOf(filters)
+	for i := 0; i < r.NumField(); i++ {
+		f := r.Field(i)
+		if f.Elem().IsValid() {
+			queries.AppendWhere(query, r.Type().Field(i).Tag.Get("boil")+" = ?", f.Elem().Interface())
+		}
+	}
+
+	queries.SetLimit(query, 1)
+
+	err := query.Bind({{$varNameSingular}}Obj)
+	if err != nil {
+		if errors.Cause(err) == sql.ErrNoRows {
+			return nil, sql.ErrNoRows
+		}
+		return nil, errors.Wrap(err, "{{.PkgName}}: unable to select from {{.Table.Name}}")
+	}
+
+	return {{$varNameSingular}}Obj, nil
+}
+
+// FindOne{{$tableNameSingular}}G retrieves a single record using filters.
+func FindOne{{$tableNameSingular}}G(filters {{$tableNameSingular}}Filter) (*{{$tableNameSingular}}, error) {
+	return FindOne{{$tableNameSingular}}(boil.GetDB(), filters)
+}
+
+// FindOne{{$tableNameSingular}}OrInit retrieves a single record using filters, or initializes a new record if one is not found.
+func FindOne{{$tableNameSingular}}OrInit(exec boil.Executor, filters {{$tableNameSingular}}Filter) (*{{$tableNameSingular}}, error) {
+	{{$varNameSingular}}Obj, err := FindOne{{$tableNameSingular}}(exec, filters)
+	if err != nil && errors.Cause(err) != sql.ErrNoRows {
+		return nil, err
+	}
+
+	if {{$varNameSingular}}Obj == nil {
+		{{$varNameSingular}}Obj = &{{$tableNameSingular}}{}
+		objR := reflect.ValueOf({{$varNameSingular}}Obj).Elem()
+		r := reflect.ValueOf(filters)
+		for i := 0; i < r.NumField(); i++ {
+			f := r.Field(i)
+			if f.Elem().IsValid() {
+				objR.FieldByName(r.Type().Field(i).Name).Set(f.Elem())
+			}
+		}
+	}
+
+	return {{$varNameSingular}}Obj, nil
+}
+
+// FindOne{{$tableNameSingular}}OrInit retrieves a single record using filters, or initializes a new record if one is not found.
+func FindOne{{$tableNameSingular}}OrInitG(filters {{$tableNameSingular}}Filter) (*{{$tableNameSingular}}, error) {
+	return FindOne{{$tableNameSingular}}OrInit(boil.GetDB(), filters)
+}
+
+// FindOne{{$tableNameSingular}}OrInit retrieves a single record using filters, or initializes and inserts a new record if one is not found.
+func FindOne{{$tableNameSingular}}OrCreate(exec boil.Executor, filters {{$tableNameSingular}}Filter) (*{{$tableNameSingular}}, error) {
+	{{$varNameSingular}}Obj, err := FindOne{{$tableNameSingular}}OrInit(exec, filters)
+	if err != nil {
+		return nil, err
+	}
+	if {{$varNameSingular}}Obj.IsNew() {
+		err := {{$varNameSingular}}Obj.Insert(exec)
+		if err != nil {
+			return nil, err
+		}
+	}
+	return {{$varNameSingular}}Obj, nil
+}
+
+// FindOne{{$tableNameSingular}}OrInit retrieves a single record using filters, or initializes and inserts a new record if one is not found.
+func FindOne{{$tableNameSingular}}OrCreateG(filters {{$tableNameSingular}}Filter) (*{{$tableNameSingular}}, error) {
+	return FindOne{{$tableNameSingular}}OrCreate(boil.GetDB(), filters)
+}
diff --git a/templates/20_exists.tpl b/templates/20_exists.tpl
index 22a67a0..2e20fa6 100644
--- a/templates/20_exists.tpl
+++ b/templates/20_exists.tpl
@@ -1,4 +1,5 @@
 {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
+{{- $varNameSingular := .Table.Name | singular | camelCase -}}
 {{- $colDefs := sqlColDefinitions .Table.Columns .Table.PKey.Columns -}}
 {{- $pkNames := $colDefs.Names | stringMap .StringFuncs.camelCase | stringMap .StringFuncs.replaceReserved -}}
 {{- $pkArgs := joinSlices " " $pkNames $colDefs.Types | join ", " -}}
@@ -51,3 +52,38 @@ func {{$tableNameSingular}}ExistsP(exec boil.Executor, {{$pkArgs}}) bool {
 
 	return e
 }
+
+// IsNew() checks if record exists in db (aka if its primary key is set).
+func (o *{{$tableNameSingular}}) IsNew() bool {
+	r := reflect.ValueOf(o).Elem()
+	for i := 0; i < r.NumField(); i++ {
+		column := r.Type().Field(i).Tag.Get("boil")
+		for _, pkColumn := range {{$varNameSingular}}PrimaryKeyColumns {
+			if column == pkColumn {
+				field := r.Field(i)
+				if field.Interface() != reflect.Zero(field.Type()).Interface() {
+					return false
+				}
+			}
+		}
+	}
+	return true
+}
+
+// Save() inserts the record if it does not exist, or updates it if it does.
+func (o *{{$tableNameSingular}}) Save(exec boil.Executor, whitelist ...string) error {
+  if o.IsNew() {
+    return o.Insert(exec, whitelist...)
+  } else {
+    return o.Update(exec, whitelist...)
+  }
+}
+
+// SaveG() inserts the record if it does not exist, or updates it if it does.
+func (o *{{$tableNameSingular}}) SaveG(whitelist ...string) error {
+  if o.IsNew() {
+    return o.InsertG(whitelist...)
+  } else {
+    return o.UpdateG(whitelist...)
+  }
+}

From ed43c9078f34416398d074fe772af8e1513289a6 Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Tue, 9 May 2017 15:30:04 -0400
Subject: [PATCH 147/179] made query structs public, added IS NULL to filter

---
 .gitignore                                 |  1 +
 templates/01_types.tpl                     |  2 +-
 templates/03_finishers.tpl                 | 20 ++++++-------
 templates/04_relationship_to_one.tpl       |  6 ++--
 templates/05_relationship_one_to_one.tpl   |  6 ++--
 templates/06_relationship_to_many.tpl      |  6 ++--
 templates/07_relationship_to_one_eager.tpl |  2 +-
 templates/13_all.tpl                       |  8 +++---
 templates/14_find.tpl                      | 20 ++++---------
 templates/16_update.tpl                    |  4 +--
 templates/18_delete.tpl                    |  6 ++--
 templates/22_query.tpl                     | 33 ++++++++++++++++++++++
 templates/singleton/boil_types.tpl         |  5 ++++
 13 files changed, 75 insertions(+), 44 deletions(-)
 create mode 100644 templates/22_query.tpl

diff --git a/.gitignore b/.gitignore
index 8f7858d..a7dc0b1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ sqlboiler.toml
 models/
 testschema.sql
 .cover
+/.idea
diff --git a/templates/01_types.tpl b/templates/01_types.tpl
index a1a1ef0..9340e42 100644
--- a/templates/01_types.tpl
+++ b/templates/01_types.tpl
@@ -21,7 +21,7 @@ type (
 	{{$tableNameSingular}}Hook func(boil.Executor, *{{$tableNameSingular}}) error
 	{{- end}}
 
-	{{$varNameSingular}}Query struct {
+	{{$tableNameSingular}}Query struct {
 		*queries.Query
 	}
 )
diff --git a/templates/03_finishers.tpl b/templates/03_finishers.tpl
index 0cc7e78..841769b 100644
--- a/templates/03_finishers.tpl
+++ b/templates/03_finishers.tpl
@@ -1,7 +1,7 @@
 {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
 {{- $varNameSingular := .Table.Name | singular | camelCase -}}
-// OneP returns a single {{$varNameSingular}} record from the query, and panics on error.
-func (q {{$varNameSingular}}Query) OneP() (*{{$tableNameSingular}}) {
+// OneP returns a single {{$tableNameSingular}} record from the query, and panics on error.
+func (q {{$tableNameSingular}}Query) OneP() (*{{$tableNameSingular}}) {
 	o, err := q.One()
 	if err != nil {
 		panic(boil.WrapErr(err))
@@ -10,8 +10,8 @@ func (q {{$varNameSingular}}Query) OneP() (*{{$tableNameSingular}}) {
 	return o
 }
 
-// One returns a single {{$varNameSingular}} record from the query.
-func (q {{$varNameSingular}}Query) One() (*{{$tableNameSingular}}, error) {
+// One returns a single {{$tableNameSingular}} record from the query.
+func (q {{$tableNameSingular}}Query) One() (*{{$tableNameSingular}}, error) {
 	o := &{{$tableNameSingular}}{}
 
 	queries.SetLimit(q.Query, 1)
@@ -34,7 +34,7 @@ func (q {{$varNameSingular}}Query) One() (*{{$tableNameSingular}}, error) {
 }
 
 // AllP returns all {{$tableNameSingular}} records from the query, and panics on error.
-func (q {{$varNameSingular}}Query) AllP() {{$tableNameSingular}}Slice {
+func (q {{$tableNameSingular}}Query) AllP() {{$tableNameSingular}}Slice {
 	o, err := q.All()
 	if err != nil {
 		panic(boil.WrapErr(err))
@@ -44,7 +44,7 @@ func (q {{$varNameSingular}}Query) AllP() {{$tableNameSingular}}Slice {
 }
 
 // All returns all {{$tableNameSingular}} records from the query.
-func (q {{$varNameSingular}}Query) All() ({{$tableNameSingular}}Slice, error) {
+func (q {{$tableNameSingular}}Query) All() ({{$tableNameSingular}}Slice, error) {
 	var o []*{{$tableNameSingular}}
 
 	err := q.Bind(&o)
@@ -66,7 +66,7 @@ func (q {{$varNameSingular}}Query) All() ({{$tableNameSingular}}Slice, error) {
 }
 
 // CountP returns the count of all {{$tableNameSingular}} records in the query, and panics on error.
-func (q {{$varNameSingular}}Query) CountP() int64 {
+func (q {{$tableNameSingular}}Query) CountP() int64 {
 	c, err := q.Count()
 	if err != nil {
 		panic(boil.WrapErr(err))
@@ -76,7 +76,7 @@ func (q {{$varNameSingular}}Query) CountP() int64 {
 }
 
 // Count returns the count of all {{$tableNameSingular}} records in the query.
-func (q {{$varNameSingular}}Query) Count() (int64, error) {
+func (q {{$tableNameSingular}}Query) Count() (int64, error) {
 	var count int64
 
 	queries.SetSelect(q.Query, nil)
@@ -91,7 +91,7 @@ func (q {{$varNameSingular}}Query) Count() (int64, error) {
 }
 
 // Exists checks if the row exists in the table, and panics on error.
-func (q {{$varNameSingular}}Query) ExistsP() bool {
+func (q {{$tableNameSingular}}Query) ExistsP() bool {
 	e, err := q.Exists()
 	if err != nil {
 		panic(boil.WrapErr(err))
@@ -101,7 +101,7 @@ func (q {{$varNameSingular}}Query) ExistsP() bool {
 }
 
 // Exists checks if the row exists in the table.
-func (q {{$varNameSingular}}Query) Exists() (bool, error) {
+func (q {{$tableNameSingular}}Query) Exists() (bool, error) {
 	var count int64
 
 	queries.SetCount(q.Query)
diff --git a/templates/04_relationship_to_one.tpl b/templates/04_relationship_to_one.tpl
index 05c75c9..9bc8c5f 100644
--- a/templates/04_relationship_to_one.tpl
+++ b/templates/04_relationship_to_one.tpl
@@ -3,14 +3,14 @@
 	{{- $dot := . -}}
 	{{- range .Table.FKeys -}}
 		{{- $txt := txtsFromFKey $dot.Tables $dot.Table . -}}
-		{{- $varNameSingular := .ForeignTable | singular | camelCase}}
+		{{- $tableNameSingular := .ForeignTable | singular | titleCase}}
 // {{$txt.Function.Name}}G pointed to by the foreign key.
-func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}G(mods ...qm.QueryMod) {{$varNameSingular}}Query {
+func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}G(mods ...qm.QueryMod) {{$tableNameSingular}}Query {
 	return o.{{$txt.Function.Name}}(boil.GetDB(), mods...)
 }
 
 // {{$txt.Function.Name}} pointed to by the foreign key.
-func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}(exec boil.Executor, mods ...qm.QueryMod) ({{$varNameSingular}}Query) {
+func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}(exec boil.Executor, mods ...qm.QueryMod) ({{$tableNameSingular}}Query) {
 	queryMods := []qm.QueryMod{
 		qm.Where("{{$txt.ForeignTable.ColumnName}}=?", o.{{$txt.LocalTable.ColumnNameGo}}),
 	}
diff --git a/templates/05_relationship_one_to_one.tpl b/templates/05_relationship_one_to_one.tpl
index e74279c..1dcd2ee 100644
--- a/templates/05_relationship_one_to_one.tpl
+++ b/templates/05_relationship_one_to_one.tpl
@@ -3,14 +3,14 @@
 	{{- $dot := . -}}
 	{{- range .Table.ToOneRelationships -}}
 		{{- $txt := txtsFromOneToOne $dot.Tables $dot.Table . -}}
-		{{- $varNameSingular := .ForeignTable | singular | camelCase}}
+		{{- $tableNameSingular := .ForeignTable | singular | titleCase}}
 // {{$txt.Function.Name}}G pointed to by the foreign key.
-func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}G(mods ...qm.QueryMod) {{$varNameSingular}}Query {
+func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}G(mods ...qm.QueryMod) {{$tableNameSingular}}Query {
 	return o.{{$txt.Function.Name}}(boil.GetDB(), mods...)
 }
 
 // {{$txt.Function.Name}} pointed to by the foreign key.
-func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}(exec boil.Executor, mods ...qm.QueryMod) ({{$varNameSingular}}Query) {
+func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}(exec boil.Executor, mods ...qm.QueryMod) ({{$tableNameSingular}}Query) {
 	queryMods := []qm.QueryMod{
 		qm.Where("{{$txt.ForeignTable.ColumnName}}=?", o.{{$txt.LocalTable.ColumnNameGo}}),
 	}
diff --git a/templates/06_relationship_to_many.tpl b/templates/06_relationship_to_many.tpl
index c108eeb..10aa842 100644
--- a/templates/06_relationship_to_many.tpl
+++ b/templates/06_relationship_to_many.tpl
@@ -3,18 +3,18 @@
 	{{- $dot := . -}}
 	{{- $table := .Table -}}
 	{{- range .Table.ToManyRelationships -}}
-		{{- $varNameSingular := .ForeignTable | singular | camelCase -}}
+		{{- $tableNameSingular := .ForeignTable | singular | titleCase -}}
 		{{- $txt := txtsFromToMany $dot.Tables $table . -}}
 		{{- $schemaForeignTable := .ForeignTable | $dot.SchemaTable}}
 // {{$txt.Function.Name}}G retrieves all the {{.ForeignTable | singular}}'s {{$txt.ForeignTable.NameHumanReadable}}
 {{- if not (eq $txt.Function.Name $txt.ForeignTable.NamePluralGo)}} via {{.ForeignColumn}} column{{- end}}.
-func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}G(mods ...qm.QueryMod) {{$varNameSingular}}Query {
+func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}G(mods ...qm.QueryMod) {{$tableNameSingular}}Query {
 	return o.{{$txt.Function.Name}}(boil.GetDB(), mods...)
 }
 
 // {{$txt.Function.Name}} retrieves all the {{.ForeignTable | singular}}'s {{$txt.ForeignTable.NameHumanReadable}} with an executor
 {{- if not (eq $txt.Function.Name $txt.ForeignTable.NamePluralGo)}} via {{.ForeignColumn}} column{{- end}}.
-func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}(exec boil.Executor, mods ...qm.QueryMod) {{$varNameSingular}}Query {
+func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}(exec boil.Executor, mods ...qm.QueryMod) {{$tableNameSingular}}Query {
 	queryMods := []qm.QueryMod{
 		qm.Select("{{id 0 | $dot.Quotes}}.*"),
 	}
diff --git a/templates/07_relationship_to_one_eager.tpl b/templates/07_relationship_to_one_eager.tpl
index dd1481a..3b24f1a 100644
--- a/templates/07_relationship_to_one_eager.tpl
+++ b/templates/07_relationship_to_one_eager.tpl
@@ -4,7 +4,7 @@
 	{{- range .Table.FKeys -}}
 		{{- $txt := txtsFromFKey $dot.Tables $dot.Table . -}}
 		{{- $varNameSingular := $dot.Table.Name | singular | camelCase -}}
-		{{- $arg := printf "maybe%s" $txt.LocalTable.NameGo -}}
+		{{- $arg := printf "maybe%s" $txt.LocalTable.NameGo}}
 // Load{{$txt.Function.Name}} allows an eager lookup of values, cached into the
 // loaded structs of the objects.
 func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singular bool, {{$arg}} interface{}) error {
diff --git a/templates/13_all.tpl b/templates/13_all.tpl
index 42cf66a..c41f19c 100644
--- a/templates/13_all.tpl
+++ b/templates/13_all.tpl
@@ -1,12 +1,12 @@
 {{- $tableNamePlural := .Table.Name | plural | titleCase -}}
-{{- $varNameSingular := .Table.Name | singular | camelCase}}
+{{- $tableNameSingular := .Table.Name | singular | titleCase}}
 // {{$tableNamePlural}}G retrieves all records.
-func {{$tableNamePlural}}G(mods ...qm.QueryMod) {{$varNameSingular}}Query {
+func {{$tableNamePlural}}G(mods ...qm.QueryMod) {{$tableNameSingular}}Query {
 	return {{$tableNamePlural}}(boil.GetDB(), mods...)
 }
 
 // {{$tableNamePlural}} retrieves all the records using an executor.
-func {{$tableNamePlural}}(exec boil.Executor, mods ...qm.QueryMod) {{$varNameSingular}}Query {
+func {{$tableNamePlural}}(exec boil.Executor, mods ...qm.QueryMod) {{$tableNameSingular}}Query {
 	mods = append(mods, qm.From("{{.Table.Name | .SchemaTable}}"))
-	return {{$varNameSingular}}Query{NewQuery(exec, mods...)}
+	return {{$tableNameSingular}}Query{NewQuery(exec, mods...)}
 }
diff --git a/templates/14_find.tpl b/templates/14_find.tpl
index 12ffa85..e177959 100644
--- a/templates/14_find.tpl
+++ b/templates/14_find.tpl
@@ -56,21 +56,13 @@ func Find{{$tableNameSingular}}P(exec boil.Executor, {{$pkArgs}}, selectCols ...
 
 // FindOne{{$tableNameSingular}} retrieves a single record using filters.
 func FindOne{{$tableNameSingular}}(exec boil.Executor, filters {{$tableNameSingular}}Filter) (*{{$tableNameSingular}}, error) {
-	{{$varNameSingular}}Obj := &{{$tableNameSingular}}{}
+	obj := &{{$tableNameSingular}}{}
 
-	query := NewQuery(exec, qm.Select("*"), qm.From("{{.Table.Name | .SchemaTable}}"))
+	err := {{$tableNameSingular}}NewQuery(exec).
+    Where(filters).
+    Limit(1).
+    Bind(obj)
 
-	r := reflect.ValueOf(filters)
-	for i := 0; i < r.NumField(); i++ {
-		f := r.Field(i)
-		if f.Elem().IsValid() {
-			queries.AppendWhere(query, r.Type().Field(i).Tag.Get("boil")+" = ?", f.Elem().Interface())
-		}
-	}
-
-	queries.SetLimit(query, 1)
-
-	err := query.Bind({{$varNameSingular}}Obj)
 	if err != nil {
 		if errors.Cause(err) == sql.ErrNoRows {
 			return nil, sql.ErrNoRows
@@ -78,7 +70,7 @@ func FindOne{{$tableNameSingular}}(exec boil.Executor, filters {{$tableNameSingu
 		return nil, errors.Wrap(err, "{{.PkgName}}: unable to select from {{.Table.Name}}")
 	}
 
-	return {{$varNameSingular}}Obj, nil
+	return obj, nil
 }
 
 // FindOne{{$tableNameSingular}}G retrieves a single record using filters.
diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index 50c7f49..bc4a6f5 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -101,14 +101,14 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 }
 
 // UpdateAllP updates all rows with matching column names, and panics on error.
-func (q {{$varNameSingular}}Query) UpdateAllP(cols M) {
+func (q {{$tableNameSingular}}Query) UpdateAllP(cols M) {
 	if err := q.UpdateAll(cols); err != nil {
 		panic(boil.WrapErr(err))
 	}
 }
 
 // UpdateAll updates all rows with the specified column values.
-func (q {{$varNameSingular}}Query) UpdateAll(cols M) error {
+func (q {{$tableNameSingular}}Query) UpdateAll(cols M) error {
 	queries.SetUpdate(q.Query, cols)
 
 	_, err := q.Query.Exec()
diff --git a/templates/18_delete.tpl b/templates/18_delete.tpl
index f2ddbb6..e9a5177 100644
--- a/templates/18_delete.tpl
+++ b/templates/18_delete.tpl
@@ -65,16 +65,16 @@ func (o *{{$tableNameSingular}}) Delete(exec boil.Executor) error {
 }
 
 // DeleteAllP deletes all rows, and panics on error.
-func (q {{$varNameSingular}}Query) DeleteAllP() {
+func (q {{$tableNameSingular}}Query) DeleteAllP() {
 	if err := q.DeleteAll(); err != nil {
 	panic(boil.WrapErr(err))
 	}
 }
 
 // DeleteAll deletes all matching rows.
-func (q {{$varNameSingular}}Query) DeleteAll() error {
+func (q {{$tableNameSingular}}Query) DeleteAll() error {
 	if q.Query == nil {
-	return errors.New("{{.PkgName}}: no {{$varNameSingular}}Query provided for delete all")
+	return errors.New("{{.PkgName}}: no {{$tableNameSingular}}Query provided for delete all")
 	}
 
 	queries.SetDelete(q.Query)
diff --git a/templates/22_query.tpl b/templates/22_query.tpl
new file mode 100644
index 0000000..512c717
--- /dev/null
+++ b/templates/22_query.tpl
@@ -0,0 +1,33 @@
+{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
+
+// {{$tableNameSingular}}NewQuery filters query results
+func {{$tableNameSingular}}NewQuery(exec boil.Executor) *{{$tableNameSingular}}Query {
+	return &{{$tableNameSingular}}Query{NewQuery(exec, qm.Select("*"), qm.From("{{.Table.Name | .SchemaTable}}"))}
+}
+
+// {{$tableNameSingular}}NewQuery filters query results
+func {{$tableNameSingular}}NewQueryG() *{{$tableNameSingular}}Query {
+	return {{$tableNameSingular}}NewQuery(boil.GetDB())
+}
+
+// Where filters query results
+func (q *{{$tableNameSingular}}Query) Where(filters {{$tableNameSingular}}Filter) *{{$tableNameSingular}}Query {
+	r := reflect.ValueOf(filters)
+	for i := 0; i < r.NumField(); i++ {
+		f := r.Field(i)
+		if f.Elem().IsValid() {
+			if nullable, ok := f.Elem().Interface().(Nullable); ok && nullable.IsZero() {
+				queries.AppendWhere(q.Query, r.Type().Field(i).Tag.Get("boil")+" IS NULL")
+			} else {
+				queries.AppendWhere(q.Query, r.Type().Field(i).Tag.Get("boil")+" = ?", f.Elem().Interface())
+			}
+		}
+	}
+	return q
+}
+
+// Limit limits query results
+func (q *{{$tableNameSingular}}Query) Limit(limit int) *{{$tableNameSingular}}Query {
+	queries.SetLimit(q.Query, limit)
+	return q
+}
\ No newline at end of file
diff --git a/templates/singleton/boil_types.tpl b/templates/singleton/boil_types.tpl
index 9bf13e8..85e05d9 100644
--- a/templates/singleton/boil_types.tpl
+++ b/templates/singleton/boil_types.tpl
@@ -1,6 +1,11 @@
 // M type is for providing columns and column values to UpdateAll.
 type M map[string]interface{}
 
+// Nullable means the value may represent an sql NULL. It is implemented by null.* types.
+type Nullable interface {
+	IsZero() bool
+}
+
 // ErrSyncFail occurs during insert when the record could not be retrieved in
 // order to populate default value information. This usually happens when LastInsertId
 // fails or there was a primary key configuration that was not resolvable.

From b160e5c1f4eddc9ac9e54e87d13da683f3cd1ede Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Wed, 10 May 2017 11:21:29 -0400
Subject: [PATCH 148/179] dont error if no rows found

---
 templates/03_finishers.tpl | 2 +-
 templates/14_find.tpl      | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/templates/03_finishers.tpl b/templates/03_finishers.tpl
index 841769b..13ea14d 100644
--- a/templates/03_finishers.tpl
+++ b/templates/03_finishers.tpl
@@ -19,7 +19,7 @@ func (q {{$tableNameSingular}}Query) One() (*{{$tableNameSingular}}, error) {
 	err := q.Bind(o)
 	if err != nil {
 		if errors.Cause(err) == sql.ErrNoRows {
-			return nil, sql.ErrNoRows
+			return nil, nil
 		}
 		return nil, errors.Wrap(err, "{{.PkgName}}: failed to execute a one query for {{.Table.Name}}")
 	}
diff --git a/templates/14_find.tpl b/templates/14_find.tpl
index e177959..b7f69db 100644
--- a/templates/14_find.tpl
+++ b/templates/14_find.tpl
@@ -36,7 +36,7 @@ func Find{{$tableNameSingular}}(exec boil.Executor, {{$pkArgs}}, selectCols ...s
 	err := q.Bind({{$varNameSingular}}Obj)
 	if err != nil {
 		if errors.Cause(err) == sql.ErrNoRows {
-			return nil, sql.ErrNoRows
+			return nil, nil
 		}
 		return nil, errors.Wrap(err, "{{.PkgName}}: unable to select from {{.Table.Name}}")
 	}
@@ -65,7 +65,7 @@ func FindOne{{$tableNameSingular}}(exec boil.Executor, filters {{$tableNameSingu
 
 	if err != nil {
 		if errors.Cause(err) == sql.ErrNoRows {
-			return nil, sql.ErrNoRows
+			return nil, nil
 		}
 		return nil, errors.Wrap(err, "{{.PkgName}}: unable to select from {{.Table.Name}}")
 	}
@@ -81,7 +81,7 @@ func FindOne{{$tableNameSingular}}G(filters {{$tableNameSingular}}Filter) (*{{$t
 // FindOne{{$tableNameSingular}}OrInit retrieves a single record using filters, or initializes a new record if one is not found.
 func FindOne{{$tableNameSingular}}OrInit(exec boil.Executor, filters {{$tableNameSingular}}Filter) (*{{$tableNameSingular}}, error) {
 	{{$varNameSingular}}Obj, err := FindOne{{$tableNameSingular}}(exec, filters)
-	if err != nil && errors.Cause(err) != sql.ErrNoRows {
+	if err != nil {
 		return nil, err
 	}
 

From 31fe8b6e1d03d29edb3c639575efc75fb2c5a970 Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Wed, 10 May 2017 15:29:02 -0400
Subject: [PATCH 149/179] model merging

---
 boilingcore/imports.go               |  7 ++-
 templates/23_merge.tpl               | 84 ++++++++++++++++++++++++++++
 templates/singleton/boil_queries.tpl | 54 ++++++++++++++++++
 3 files changed, 144 insertions(+), 1 deletion(-)
 create mode 100644 templates/23_merge.tpl

diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index 1fbca14..fc148c7 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -179,11 +179,16 @@ func newImporter() importer {
 	}
 
 	imp.Singleton = mapImports{
-		"boil_queries": {
+		"boil_queries": imports{
+			standard: importList{
+				`"database/sql"`,
+				`"strings"`,
+			},
 			thirdParty: importList{
 				`"github.com/lbryio/sqlboiler/boil"`,
 				`"github.com/lbryio/sqlboiler/queries"`,
 				`"github.com/lbryio/sqlboiler/queries/qm"`,
+				`"github.com/pkg/errors"`,
 			},
 		},
 		"boil_types": {
diff --git a/templates/23_merge.tpl b/templates/23_merge.tpl
new file mode 100644
index 0000000..c7e27f5
--- /dev/null
+++ b/templates/23_merge.tpl
@@ -0,0 +1,84 @@
+{{- $tableNamePlural := .Table.Name | plural | titleCase -}}
+{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
+{{- if .Table.IsJoinTable -}}
+{{- else -}}
+	{{- $dot := . }}
+// Merge combines two {{$tableNamePlural}} into one. The primary record will be kept, and the secondary will be deleted.
+func Merge{{$tableNamePlural}}(exec boil.Executor, primaryID uint64, secondaryID uint64) error {
+	txdb, ok := exec.(boil.Beginner)
+	if !ok {
+		return errors.New("database does not support transactions")
+	}
+
+	tx, txErr := txdb.Begin()
+	if txErr != nil {
+		return txErr
+	}
+
+  primary, err := Find{{$tableNameSingular}}(tx, primaryID)
+  if err != nil {
+    tx.Rollback()
+    return err
+  }
+	if primary == nil {
+		return errors.New("Primary {{$tableNameSingular}} not found")
+	}
+
+  secondary, err := Find{{$tableNameSingular}}(tx, secondaryID)
+  if err != nil {
+    tx.Rollback()
+    return err
+  }
+	if secondary == nil {
+		return errors.New("Secondary {{$tableNameSingular}} not found")
+	}
+
+  relatedFields := map[string]string{
+	{{- range .Tables -}}
+	  {{- range .FKeys -}}
+	    {{- if eq $dot.Table.Name .ForeignTable }}
+		  "{{.Table }}": "{{ .Column}}",
+      {{- end -}}
+    {{- end -}}
+  {{- end }}
+  }
+  err = mergeModels(tx, primaryID, secondaryID, relatedFields)
+  if err != nil {
+    tx.Rollback()
+    return err
+  }
+
+	pr := reflect.ValueOf(primary)
+	sr := reflect.ValueOf(secondary)
+	// for any column thats null on the primary and not null on the secondary, copy from secondary to primary
+	for i := 0; i < sr.Elem().NumField(); i++ {
+		pf := pr.Elem().Field(i)
+		sf := sr.Elem().Field(i)
+		if sf.IsValid() {
+			if nullable, ok := sf.Interface().(Nullable); ok && !nullable.IsZero() && pf.Interface().(Nullable).IsZero() {
+				pf.Set(sf)
+			}
+		}
+	}
+
+	err = primary.Update(tx)
+	if err != nil {
+		tx.Rollback()
+		return errors.WithStack(err)
+	}
+
+	err = secondary.Delete(tx)
+	if err != nil {
+		tx.Rollback()
+		return errors.WithStack(err)
+	}
+
+  tx.Commit()
+  return nil
+}
+
+// Merge combines two {{$tableNamePlural}} into one. The primary record will be kept, and the secondary will be deleted.
+func Merge{{$tableNamePlural}}G(primaryID uint64, secondaryID uint64) error {
+  return Merge{{$tableNamePlural}}(boil.GetDB(), primaryID, secondaryID)
+}
+{{- end -}}{{/* join table */}}
\ No newline at end of file
diff --git a/templates/singleton/boil_queries.tpl b/templates/singleton/boil_queries.tpl
index 3883e8e..d129e43 100644
--- a/templates/singleton/boil_queries.tpl
+++ b/templates/singleton/boil_queries.tpl
@@ -19,3 +19,57 @@ func NewQuery(exec boil.Executor, mods ...qm.QueryMod) *queries.Query {
 
 	return q
 }
+
+func mergeModels(tx *sql.Tx, primaryID uint64, secondaryID uint64, relatedFields map[string]string) error {
+	if len(relatedFields) < 1 {
+    return nil
+  }
+
+  for table, column := range relatedFields {
+    // TODO: use NewQuery here, not plain sql
+    query := "UPDATE " + table + " SET " + column + " = ? WHERE " + column + " = ?"
+    _, err := tx.Exec(query, primaryID, secondaryID)
+    if err != nil {
+      return errors.WithStack(err)
+    }
+  }
+  return checkMerge(tx, relatedFields)
+}
+
+func checkMerge(tx *sql.Tx, fields map[string]string) error {
+	columns := []interface{}{}
+	seenColumns := map[string]bool{}
+	placeholders := []string{}
+	for _, column := range fields {
+		if _, ok := seenColumns[column]; !ok {
+			columns = append(columns, column)
+			seenColumns[column] = true
+			placeholders = append(placeholders, "?")
+
+		}
+	}
+
+	placeholder := strings.Join(placeholders, ", ")
+
+	q := `SELECT table_name, column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND column_name IN (` + placeholder + `)`
+	rows, err := tx.Query(q, columns...)
+	defer rows.Close()
+	if err != nil {
+		return errors.WithStack(err)
+	}
+
+	for rows.Next() {
+		var tableName string
+		var columnName string
+		err = rows.Scan(&tableName, &columnName)
+		if err != nil {
+			return errors.WithStack(err)
+		}
+
+		if _, exists := fields[tableName]; !exists {
+			return errors.New("Missing merge for " + tableName + "." + columnName)
+		}
+	}
+
+	return nil
+}

From 912a689701a945ccd9034c4227b508dfca353095 Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Thu, 11 May 2017 17:42:20 -0400
Subject: [PATCH 150/179] added unique key detection (mysql only for now),
 improved merging

---
 bdb/drivers/mock.go                  |   4 +
 bdb/drivers/mssql.go                 |   6 +-
 bdb/drivers/mysql.go                 |  42 +++++++++-
 bdb/drivers/postgres.go              |   8 +-
 bdb/interface.go                     |   5 ++
 bdb/keys.go                          |   7 ++
 bdb/table.go                         |   1 +
 boilingcore/imports.go               |   3 +-
 boilingcore/templates.go             |   2 +-
 templates/23_merge.tpl               |  23 +++++-
 templates/singleton/boil_queries.tpl | 116 ++++++++++++++++++++-------
 templates/singleton/boil_types.tpl   |  16 ++++
 12 files changed, 195 insertions(+), 38 deletions(-)

diff --git a/bdb/drivers/mock.go b/bdb/drivers/mock.go
index 7d14f2a..810eb48 100644
--- a/bdb/drivers/mock.go
+++ b/bdb/drivers/mock.go
@@ -58,6 +58,10 @@ func (m *MockDriver) Columns(schema, tableName string) ([]bdb.Column, error) {
 	}[tableName], nil
 }
 
+func (m *MockDriver) UniqueKeyInfo(schema, tableName string) ([]bdb.UniqueKey, error) {
+	return []bdb.UniqueKey{}, nil
+}
+
 // ForeignKeyInfo returns a list of mock foreignkeys
 func (m *MockDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) {
 	return map[string][]bdb.ForeignKey{
diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index e59330b..70b9ed9 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -7,8 +7,8 @@ import (
 	"strings"
 
 	_ "github.com/denisenkom/go-mssqldb"
-	"github.com/pkg/errors"
 	"github.com/lbryio/sqlboiler/bdb"
+	"github.com/pkg/errors"
 )
 
 // MSSQLDriver holds the database connection string and a handle
@@ -241,6 +241,10 @@ func (m *MSSQLDriver) PrimaryKeyInfo(schema, tableName string) (*bdb.PrimaryKey,
 	return pkey, nil
 }
 
+func (m *MSSQLDriver) UniqueKeyInfo(schema, tableName string) ([]bdb.UniqueKey, error) {
+	return []bdb.UniqueKey{}, errors.New("not implemented")
+}
+
 // ForeignKeyInfo retrieves the foreign keys for a given table name.
 func (m *MSSQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) {
 	var fkeys []bdb.ForeignKey
diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go
index bb73574..6a20ba0 100644
--- a/bdb/drivers/mysql.go
+++ b/bdb/drivers/mysql.go
@@ -7,8 +7,8 @@ import (
 	"strings"
 
 	"github.com/go-sql-driver/mysql"
-	"github.com/pkg/errors"
 	"github.com/lbryio/sqlboiler/bdb"
+	"github.com/pkg/errors"
 )
 
 // TinyintAsBool is a global that is set from main.go if a user specifies
@@ -232,6 +232,46 @@ func (m *MySQLDriver) PrimaryKeyInfo(schema, tableName string) (*bdb.PrimaryKey,
 	return pkey, nil
 }
 
+// UniqueKeyInfo retrieves the unique keys for a given table name.
+func (m *MySQLDriver) UniqueKeyInfo(schema, tableName string) ([]bdb.UniqueKey, error) {
+	var ukeys []bdb.UniqueKey
+
+	query := `
+	select tc.table_name, tc.constraint_name, GROUP_CONCAT(kcu.column_name)
+	from information_schema.table_constraints tc
+	left join information_schema.key_column_usage kcu on tc.constraint_name = kcu.constraint_name and tc.table_name = kcu.table_name and tc.table_schema = kcu.table_schema
+	where tc.table_schema = ? and tc.table_name = ? and tc.constraint_type = "UNIQUE"
+	group by tc.table_name, tc.constraint_name
+	`
+
+	var rows *sql.Rows
+	var err error
+	if rows, err = m.dbConn.Query(query, schema, tableName); err != nil {
+		return nil, err
+	}
+
+	for rows.Next() {
+		var ukey bdb.UniqueKey
+		var columns string
+
+		//ukey.Table = tableName
+		err = rows.Scan(&ukey.Table, &ukey.Name, &columns)
+		if err != nil {
+			return nil, err
+		}
+
+		ukey.Columns = strings.Split(columns, ",")
+
+		ukeys = append(ukeys, ukey)
+	}
+
+	if err = rows.Err(); err != nil {
+		return nil, err
+	}
+
+	return ukeys, nil
+}
+
 // ForeignKeyInfo retrieves the foreign keys for a given table name.
 func (m *MySQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) {
 	var fkeys []bdb.ForeignKey
diff --git a/bdb/drivers/postgres.go b/bdb/drivers/postgres.go
index ad73a2e..4b6a9f4 100644
--- a/bdb/drivers/postgres.go
+++ b/bdb/drivers/postgres.go
@@ -8,10 +8,10 @@ import (
 
 	// Side-effect import sql driver
 
-	_ "github.com/lib/pq"
-	"github.com/pkg/errors"
 	"github.com/lbryio/sqlboiler/bdb"
 	"github.com/lbryio/sqlboiler/strmangle"
+	_ "github.com/lib/pq"
+	"github.com/pkg/errors"
 )
 
 // PostgresDriver holds the database connection string and a handle
@@ -266,6 +266,10 @@ func (p *PostgresDriver) PrimaryKeyInfo(schema, tableName string) (*bdb.PrimaryK
 	return pkey, nil
 }
 
+func (p *PostgresDriver) UniqueKeyInfo(schema, tableName string) ([]bdb.UniqueKey, error) {
+	return []bdb.UniqueKey{}, errors.New("not implemented")
+}
+
 // ForeignKeyInfo retrieves the foreign keys for a given table name.
 func (p *PostgresDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) {
 	var fkeys []bdb.ForeignKey
diff --git a/bdb/interface.go b/bdb/interface.go
index dfb33bc..1fe179a 100644
--- a/bdb/interface.go
+++ b/bdb/interface.go
@@ -9,6 +9,7 @@ type Interface interface {
 	TableNames(schema string, whitelist, blacklist []string) ([]string, error)
 	Columns(schema, tableName string) ([]Column, error)
 	PrimaryKeyInfo(schema, tableName string) (*PrimaryKey, error)
+	UniqueKeyInfo(schema, tableName string) ([]UniqueKey, error)
 	ForeignKeyInfo(schema, tableName string) ([]ForeignKey, error)
 
 	// TranslateColumnType takes a Database column type and returns a go column type.
@@ -63,6 +64,10 @@ func Tables(db Interface, schema string, whitelist, blacklist []string) ([]Table
 			return nil, errors.Wrapf(err, "unable to fetch table pkey info (%s)", name)
 		}
 
+		if t.UKeys, err = db.UniqueKeyInfo(schema, name); err != nil {
+			return nil, errors.Wrapf(err, "unable to fetch table ukey info (%s)", name)
+		}
+
 		if t.FKeys, err = db.ForeignKeyInfo(schema, name); err != nil {
 			return nil, errors.Wrapf(err, "unable to fetch table fkey info (%s)", name)
 		}
diff --git a/bdb/keys.go b/bdb/keys.go
index 909ada2..8007843 100644
--- a/bdb/keys.go
+++ b/bdb/keys.go
@@ -8,6 +8,13 @@ type PrimaryKey struct {
 	Columns []string
 }
 
+// UniqueKey represents a unique key constraint in a database
+type UniqueKey struct {
+	Table   string
+	Name    string
+	Columns []string
+}
+
 // ForeignKey represents a foreign key constraint in a database
 type ForeignKey struct {
 	Table    string
diff --git a/bdb/table.go b/bdb/table.go
index 62dcd32..d5cbb50 100644
--- a/bdb/table.go
+++ b/bdb/table.go
@@ -11,6 +11,7 @@ type Table struct {
 	Columns    []Column
 
 	PKey  *PrimaryKey
+	UKeys []UniqueKey
 	FKeys []ForeignKey
 
 	IsJoinTable bool
diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index fc148c7..62b15bb 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -182,12 +182,13 @@ func newImporter() importer {
 		"boil_queries": imports{
 			standard: importList{
 				`"database/sql"`,
-				`"strings"`,
+				`"fmt"`,
 			},
 			thirdParty: importList{
 				`"github.com/lbryio/sqlboiler/boil"`,
 				`"github.com/lbryio/sqlboiler/queries"`,
 				`"github.com/lbryio/sqlboiler/queries/qm"`,
+				`"github.com/lbryio/sqlboiler/strmangle"`,
 				`"github.com/pkg/errors"`,
 			},
 		},
diff --git a/boilingcore/templates.go b/boilingcore/templates.go
index 62c0ae5..86c78ce 100644
--- a/boilingcore/templates.go
+++ b/boilingcore/templates.go
@@ -8,10 +8,10 @@ import (
 	"strings"
 	"text/template"
 
-	"github.com/pkg/errors"
 	"github.com/lbryio/sqlboiler/bdb"
 	"github.com/lbryio/sqlboiler/queries"
 	"github.com/lbryio/sqlboiler/strmangle"
+	"github.com/pkg/errors"
 )
 
 // templateData for sqlboiler templates
diff --git a/templates/23_merge.tpl b/templates/23_merge.tpl
index c7e27f5..35ca404 100644
--- a/templates/23_merge.tpl
+++ b/templates/23_merge.tpl
@@ -33,16 +33,33 @@ func Merge{{$tableNamePlural}}(exec boil.Executor, primaryID uint64, secondaryID
 		return errors.New("Secondary {{$tableNameSingular}} not found")
 	}
 
-  relatedFields := map[string]string{
+  foreignKeys := []foreignKey{
 	{{- range .Tables -}}
 	  {{- range .FKeys -}}
 	    {{- if eq $dot.Table.Name .ForeignTable }}
-		  "{{.Table }}": "{{ .Column}}",
+		  {foreignTable: "{{.Table}}", foreignColumn: "{{.Column}}"},
       {{- end -}}
     {{- end -}}
   {{- end }}
   }
-  err = mergeModels(tx, primaryID, secondaryID, relatedFields)
+
+  conflictingKeys := []conflictingUniqueKey{
+    {{- range .Tables -}}
+      {{- $table := . -}}
+      {{- range .FKeys -}}
+        {{- $fk := . -}}
+        {{- if eq $dot.Table.Name .ForeignTable -}}
+          {{- range $table.UKeys -}}
+            {{- if setInclude $fk.Column .Columns }}
+              {table: "{{$fk.Table}}", objectIdColumn: "{{$fk.Column}}", columns: []string{`{{ .Columns | join "`,`" }}`}},
+            {{- end -}}
+          {{- end -}}
+        {{- end -}}
+      {{- end -}}
+    {{- end }}
+  }
+
+  err = mergeModels(tx, primaryID, secondaryID, foreignKeys, conflictingKeys)
   if err != nil {
     tx.Rollback()
     return err
diff --git a/templates/singleton/boil_queries.tpl b/templates/singleton/boil_queries.tpl
index d129e43..8ff4edd 100644
--- a/templates/singleton/boil_queries.tpl
+++ b/templates/singleton/boil_queries.tpl
@@ -20,39 +20,97 @@ func NewQuery(exec boil.Executor, mods ...qm.QueryMod) *queries.Query {
 	return q
 }
 
-func mergeModels(tx *sql.Tx, primaryID uint64, secondaryID uint64, relatedFields map[string]string) error {
-	if len(relatedFields) < 1 {
-    return nil
-  }
-
-  for table, column := range relatedFields {
-    // TODO: use NewQuery here, not plain sql
-    query := "UPDATE " + table + " SET " + column + " = ? WHERE " + column + " = ?"
-    _, err := tx.Exec(query, primaryID, secondaryID)
-    if err != nil {
-      return errors.WithStack(err)
-    }
-  }
-  return checkMerge(tx, relatedFields)
-}
-
-func checkMerge(tx *sql.Tx, fields map[string]string) error {
-	columns := []interface{}{}
-	seenColumns := map[string]bool{}
-	placeholders := []string{}
-	for _, column := range fields {
-		if _, ok := seenColumns[column]; !ok {
-			columns = append(columns, column)
-			seenColumns[column] = true
-			placeholders = append(placeholders, "?")
+func mergeModels(tx *sql.Tx, primaryID uint64, secondaryID uint64, foreignKeys []foreignKey, conflictingKeys []conflictingUniqueKey) error {
+	if len(foreignKeys) < 1 {
+		return nil
+	}
+	var err error
 
+	for _, conflict := range conflictingKeys {
+		err = deleteConflictsBeforeMerge(tx, conflict, primaryID, secondaryID)
+		if err != nil {
+			return errors.WithStack(err)
 		}
 	}
 
-	placeholder := strings.Join(placeholders, ", ")
+	for _, fk := range foreignKeys {
+		// TODO: use NewQuery here, not plain sql
+		query := fmt.Sprintf(
+			"UPDATE %s SET %s = %s WHERE %s = %s",
+			fk.foreignTable, fk.foreignColumn, strmangle.Placeholders(dialect.IndexPlaceholders, 1, 1, 1),
+			fk.foreignColumn, strmangle.Placeholders(dialect.IndexPlaceholders, 1, 2, 1),
+		)
+		_, err = tx.Exec(query, primaryID, secondaryID)
+		if err != nil {
+			return errors.WithStack(err)
+		}
+	}
+	return checkMerge(tx, foreignKeys)
+}
 
-	q := `SELECT table_name, column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND column_name IN (` + placeholder + `)`
-	rows, err := tx.Query(q, columns...)
+func deleteConflictsBeforeMerge(tx *sql.Tx, conflict conflictingUniqueKey, primaryID uint64, secondaryID uint64) error {
+	conflictingColumns := strmangle.SetComplement(conflict.columns, []string{conflict.objectIdColumn})
+
+	if len(conflictingColumns) < 1 {
+		return nil
+	} else if len(conflictingColumns) > 1 {
+		return errors.New("this doesnt work for unique keys with more than two columns (yet)")
+	}
+
+	query := fmt.Sprintf(
+		"SELECT %s FROM %s WHERE %s IN (%s) GROUP BY %s HAVING count(distinct %s) > 1",
+		conflictingColumns[0], conflict.table, conflict.objectIdColumn,
+		strmangle.Placeholders(dialect.IndexPlaceholders, 2, 1, 1),
+		conflictingColumns[0], conflict.objectIdColumn,
+	)
+
+	rows, err := tx.Query(query, primaryID, secondaryID)
+	defer rows.Close()
+	if err != nil {
+		return errors.WithStack(err)
+	}
+
+	args := []interface{}{secondaryID}
+	for rows.Next() {
+		var value string
+		err = rows.Scan(&value)
+		if err != nil {
+			return errors.WithStack(err)
+		}
+		args = append(args, value)
+	}
+
+	query = fmt.Sprintf(
+		"DELETE FROM %s WHERE %s = %s AND %s IN (%s)",
+		conflict.table, conflict.objectIdColumn, strmangle.Placeholders(dialect.IndexPlaceholders, 1, 1, 1),
+		conflictingColumns[0], strmangle.Placeholders(dialect.IndexPlaceholders, len(args)-1, 2, 1),
+	)
+
+	_, err = tx.Exec(query, args...)
+	if err != nil {
+		return errors.WithStack(err)
+	}
+	return nil
+}
+
+func checkMerge(tx *sql.Tx, foreignKeys []foreignKey) error {
+	uniqueColumns := []interface{}{}
+	uniqueColumnNames := map[string]bool{}
+	handledTablesColumns := map[string]bool{}
+
+	for _, fk := range foreignKeys {
+		handledTablesColumns[fk.foreignTable+"."+fk.foreignColumn] = true
+		if _, ok := uniqueColumnNames[fk.foreignColumn]; !ok {
+			uniqueColumns = append(uniqueColumns, fk.foreignColumn)
+			uniqueColumnNames[fk.foreignColumn] = true
+		}
+	}
+
+	q := fmt.Sprintf(
+		`SELECT table_name, column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA=DATABASE() AND column_name IN (%s)`,
+		strmangle.Placeholders(dialect.IndexPlaceholders, len(uniqueColumns), 1, 1),
+	)
+	rows, err := tx.Query(q, uniqueColumns...)
 	defer rows.Close()
 	if err != nil {
 		return errors.WithStack(err)
@@ -66,7 +124,7 @@ func checkMerge(tx *sql.Tx, fields map[string]string) error {
 			return errors.WithStack(err)
 		}
 
-		if _, exists := fields[tableName]; !exists {
+		if _, exists := handledTablesColumns[tableName+"."+columnName]; !exists {
 			return errors.New("Missing merge for " + tableName + "." + columnName)
 		}
 	}
diff --git a/templates/singleton/boil_types.tpl b/templates/singleton/boil_types.tpl
index 85e05d9..aa61bf9 100644
--- a/templates/singleton/boil_types.tpl
+++ b/templates/singleton/boil_types.tpl
@@ -6,6 +6,22 @@ type Nullable interface {
 	IsZero() bool
 }
 
+// foreignKey connects two tables. When merging records, foreign keys from secondary record must
+// be reassigned to primary record.
+type foreignKey struct {
+	foreignTable  string
+	foreignColumn string
+}
+
+// conflictingUniqueKey records a merge conflict. If two rows exist with the same value in the
+// conflicting column for two records being merged, one row must be deleted.
+type conflictingUniqueKey struct {
+	table          string
+	objectIdColumn string
+	columns        []string
+}
+
+
 // ErrSyncFail occurs during insert when the record could not be retrieved in
 // order to populate default value information. This usually happens when LastInsertId
 // fails or there was a primary key configuration that was not resolvable.

From 09c585cdb1056fc48c59541b0c66f20a81282a25 Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Thu, 1 Jun 2017 09:58:50 -0400
Subject: [PATCH 151/179] dont run delete query when there's nothing to delete

---
 templates/singleton/boil_queries.tpl | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/templates/singleton/boil_queries.tpl b/templates/singleton/boil_queries.tpl
index 8ff4edd..248fae1 100644
--- a/templates/singleton/boil_queries.tpl
+++ b/templates/singleton/boil_queries.tpl
@@ -80,6 +80,11 @@ func deleteConflictsBeforeMerge(tx *sql.Tx, conflict conflictingUniqueKey, prima
 		args = append(args, value)
 	}
 
+	// if no rows found, no need to delete anything
+	if len(args) < 2 {
+		return nil
+	}
+
 	query = fmt.Sprintf(
 		"DELETE FROM %s WHERE %s = %s AND %s IN (%s)",
 		conflict.table, conflict.objectIdColumn, strmangle.Placeholders(dialect.IndexPlaceholders, 1, 1, 1),

From ed423a360605cf1d4309cc78d969fce5674d7aea Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Mon, 12 Jun 2017 14:02:04 -0400
Subject: [PATCH 152/179] detect autoincrement column, fix lastID in upsert
 when update doesnt change anything

---
 bdb/drivers/mock.go       |  4 ++++
 bdb/drivers/mssql.go      |  4 ++++
 bdb/drivers/mysql.go      | 32 ++++++++++++++++++++++++++++++++
 bdb/drivers/postgres.go   |  4 ++++
 bdb/interface.go          |  5 +++++
 bdb/table.go              |  4 +++-
 main.go                   |  6 +++---
 queries/query_builders.go |  7 ++++++-
 templates/01_types.tpl    |  1 +
 templates/17_upsert.tpl   |  2 +-
 10 files changed, 63 insertions(+), 6 deletions(-)

diff --git a/bdb/drivers/mock.go b/bdb/drivers/mock.go
index 810eb48..d8a5aa0 100644
--- a/bdb/drivers/mock.go
+++ b/bdb/drivers/mock.go
@@ -62,6 +62,10 @@ func (m *MockDriver) UniqueKeyInfo(schema, tableName string) ([]bdb.UniqueKey, e
 	return []bdb.UniqueKey{}, nil
 }
 
+func (m *MockDriver) AutoincrementInfo(schema, tableName string) (string, error) {
+	return "", nil
+}
+
 // ForeignKeyInfo returns a list of mock foreignkeys
 func (m *MockDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) {
 	return map[string][]bdb.ForeignKey{
diff --git a/bdb/drivers/mssql.go b/bdb/drivers/mssql.go
index 70b9ed9..79f3010 100644
--- a/bdb/drivers/mssql.go
+++ b/bdb/drivers/mssql.go
@@ -245,6 +245,10 @@ func (m *MSSQLDriver) UniqueKeyInfo(schema, tableName string) ([]bdb.UniqueKey,
 	return []bdb.UniqueKey{}, errors.New("not implemented")
 }
 
+func (m *MSSQLDriver) AutoincrementInfo(schema, tableName string) (string, error) {
+	return "", errors.New("not implemented")
+}
+
 // ForeignKeyInfo retrieves the foreign keys for a given table name.
 func (m *MSSQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) {
 	var fkeys []bdb.ForeignKey
diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go
index 6a20ba0..41510ee 100644
--- a/bdb/drivers/mysql.go
+++ b/bdb/drivers/mysql.go
@@ -272,6 +272,38 @@ func (m *MySQLDriver) UniqueKeyInfo(schema, tableName string) ([]bdb.UniqueKey,
 	return ukeys, nil
 }
 
+// AutoincrementInfo retrieves the autoincrement column for a given table name, if one exists.
+func (m *MySQLDriver) AutoincrementInfo(schema, tableName string) (string, error) {
+	query := `
+	select column_name
+	from information_schema.columns
+	where table_schema = ? and table_name = ? and extra like "%auto_increment%"
+	`
+
+	var rows *sql.Rows
+	var err error
+	if rows, err = m.dbConn.Query(query, schema, tableName); err != nil {
+		return "", err
+	}
+
+	for rows.Next() {
+		var column string
+
+		err = rows.Scan(&column)
+		if err != nil {
+			return "", err
+		}
+
+		return column, nil
+	}
+
+	if err = rows.Err(); err != nil {
+		return "", err
+	}
+
+	return "", nil
+}
+
 // ForeignKeyInfo retrieves the foreign keys for a given table name.
 func (m *MySQLDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) {
 	var fkeys []bdb.ForeignKey
diff --git a/bdb/drivers/postgres.go b/bdb/drivers/postgres.go
index 4b6a9f4..9af7edd 100644
--- a/bdb/drivers/postgres.go
+++ b/bdb/drivers/postgres.go
@@ -270,6 +270,10 @@ func (p *PostgresDriver) UniqueKeyInfo(schema, tableName string) ([]bdb.UniqueKe
 	return []bdb.UniqueKey{}, errors.New("not implemented")
 }
 
+func (p *PostgresDriver) AutoincrementInfo(schema, tableName string) (string, error) {
+	return "", errors.New("not implemented")
+}
+
 // ForeignKeyInfo retrieves the foreign keys for a given table name.
 func (p *PostgresDriver) ForeignKeyInfo(schema, tableName string) ([]bdb.ForeignKey, error) {
 	var fkeys []bdb.ForeignKey
diff --git a/bdb/interface.go b/bdb/interface.go
index 1fe179a..7f4baa5 100644
--- a/bdb/interface.go
+++ b/bdb/interface.go
@@ -10,6 +10,7 @@ type Interface interface {
 	Columns(schema, tableName string) ([]Column, error)
 	PrimaryKeyInfo(schema, tableName string) (*PrimaryKey, error)
 	UniqueKeyInfo(schema, tableName string) ([]UniqueKey, error)
+	AutoincrementInfo(schema, tableName string) (string, error)
 	ForeignKeyInfo(schema, tableName string) ([]ForeignKey, error)
 
 	// TranslateColumnType takes a Database column type and returns a go column type.
@@ -72,6 +73,10 @@ func Tables(db Interface, schema string, whitelist, blacklist []string) ([]Table
 			return nil, errors.Wrapf(err, "unable to fetch table fkey info (%s)", name)
 		}
 
+		if t.AutoIncrementColumn, err = db.AutoincrementInfo(schema, name); err != nil {
+			return nil, errors.Wrapf(err, "unable to fetch table autoincrement info (%s)", name)
+		}
+
 		setIsJoinTable(&t)
 
 		tables = append(tables, t)
diff --git a/bdb/table.go b/bdb/table.go
index d5cbb50..13355aa 100644
--- a/bdb/table.go
+++ b/bdb/table.go
@@ -8,7 +8,9 @@ type Table struct {
 	// For dbs with real schemas, like Postgres.
 	// Example value: "schema_name"."table_name"
 	SchemaName string
-	Columns    []Column
+
+	Columns             []Column
+	AutoIncrementColumn string
 
 	PKey  *PrimaryKey
 	UKeys []UniqueKey
diff --git a/main.go b/main.go
index 5103116..8344e57 100644
--- a/main.go
+++ b/main.go
@@ -8,13 +8,13 @@ import (
 	"strings"
 
 	"github.com/kat-co/vala"
-	"github.com/spf13/cobra"
-	"github.com/spf13/viper"
 	"github.com/lbryio/sqlboiler/bdb/drivers"
 	"github.com/lbryio/sqlboiler/boilingcore"
+	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
 )
 
-const sqlBoilerVersion = "2.3.0"
+const sqlBoilerVersion = "2.4.0+lbry"
 
 var (
 	cmdState  *boilingcore.State
diff --git a/queries/query_builders.go b/queries/query_builders.go
index d221aca..f884f91 100644
--- a/queries/query_builders.go
+++ b/queries/query_builders.go
@@ -190,7 +190,7 @@ func buildUpdateQuery(q *Query) (*bytes.Buffer, []interface{}) {
 }
 
 // BuildUpsertQueryMySQL builds a SQL statement string using the upsertData provided.
-func BuildUpsertQueryMySQL(dia Dialect, tableName string, update, whitelist []string) string {
+func BuildUpsertQueryMySQL(dia Dialect, tableName string, update, whitelist []string, autoIncrementCol string) string {
 	whitelist = strmangle.IdentQuoteSlice(dia.LQ, dia.RQ, whitelist)
 
 	buf := strmangle.GetBuffer()
@@ -220,6 +220,11 @@ func BuildUpsertQueryMySQL(dia Dialect, tableName string, update, whitelist []st
 		strmangle.Placeholders(dia.IndexPlaceholders, len(whitelist), 1, 1),
 	)
 
+	// https://stackoverflow.com/questions/778534/mysql-on-duplicate-key-last-insert-id
+	if autoIncrementCol != "" {
+		buf.WriteString(autoIncrementCol + " = LAST_INSERT_ID(" + autoIncrementCol + "), ")
+	}
+
 	for i, v := range update {
 		if i != 0 {
 			buf.WriteByte(',')
diff --git a/templates/01_types.tpl b/templates/01_types.tpl
index 9340e42..5aac35f 100644
--- a/templates/01_types.tpl
+++ b/templates/01_types.tpl
@@ -10,6 +10,7 @@ var (
 	{{$varNameSingular}}ColumnsWithoutDefault = []string{{"{"}}{{.Table.Columns | filterColumnsByDefault false | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
 	{{$varNameSingular}}ColumnsWithDefault    = []string{{"{"}}{{.Table.Columns | filterColumnsByDefault true | columnNames | stringMap .StringFuncs.quoteWrap | join ","}}{{"}"}}
 	{{$varNameSingular}}PrimaryKeyColumns     = []string{{"{"}}{{.Table.PKey.Columns | stringMap .StringFuncs.quoteWrap | join ", "}}{{"}"}}
+	{{$varNameSingular}}AutoIncrementColumn   = "{{.Table.AutoIncrementColumn }}"
 )
 
 type (
diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index f3d51e7..dbce58c 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -115,7 +115,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 		}
 		cache.query = queries.BuildUpsertQueryPostgres(dialect, "{{$schemaTable}}", updateOnConflict, ret, update, conflict, insert)
 		{{else if eq .DriverName "mysql"}}
-		cache.query = queries.BuildUpsertQueryMySQL(dialect, "{{.Table.Name}}", update, insert)
+		cache.query = queries.BuildUpsertQueryMySQL(dialect, "{{.Table.Name}}", update, insert, {{$varNameSingular}}AutoIncrementColumn)
 		cache.retQuery = fmt.Sprintf(
 			"SELECT %s FROM {{.LQ}}{{.Table.Name}}{{.RQ}} WHERE {{whereClause .LQ .RQ 0 .Table.PKey.Columns}}",
 			strings.Join(strmangle.IdentQuoteSlice(dialect.LQ, dialect.RQ, ret), ","),

From 05c7f7d06a7f9c1a1c845a91ee04c9020e8e7ba3 Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Thu, 6 Jul 2017 15:15:00 -0400
Subject: [PATCH 153/179] switch to more complete null package, implement nicer
 sql logging

---
 boilingcore/imports.go                        | 42 +++++----
 boilingcore/imports_test.go                   | 10 +-
 queries/helpers_test.go                       |  2 +-
 queries/query.go                              | 94 +++++++++++++++++--
 randomize/randomize.go                        |  2 +-
 randomize/randomize_test.go                   |  2 +-
 templates/07_relationship_to_one_eager.tpl    |  6 +-
 .../08_relationship_one_to_one_eager.tpl      |  6 +-
 templates/09_relationship_to_many_eager.tpl   |  6 +-
 templates/10_relationship_to_one_setops.tpl   |  7 +-
 .../11_relationship_one_to_one_setops.tpl     |  7 +-
 templates/12_relationship_to_many_setops.tpl  | 28 ++++--
 templates/15_insert.tpl                       | 14 ++-
 templates/16_update.tpl                       | 14 ++-
 templates/17_upsert.tpl                       | 14 ++-
 templates/18_delete.tpl                       | 40 ++++----
 templates/20_exists.tpl                       |  7 +-
 templates/22_query.tpl                        |  2 +-
 templates/23_merge.tpl                        |  2 +-
 templates/singleton/boil_queries.tpl          | 66 +++++++++++++
 templates/singleton/boil_types.tpl            |  5 -
 21 files changed, 291 insertions(+), 85 deletions(-)

diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index 62b15bb..2c31c63 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -170,11 +170,12 @@ func newImporter() importer {
 			`"time"`,
 		},
 		thirdParty: importList{
-			`"github.com/pkg/errors"`,
+			`"github.com/lbryio/null.go"`,
 			`"github.com/lbryio/sqlboiler/boil"`,
 			`"github.com/lbryio/sqlboiler/queries"`,
 			`"github.com/lbryio/sqlboiler/queries/qm"`,
 			`"github.com/lbryio/sqlboiler/strmangle"`,
+			`"github.com/pkg/errors"`,
 		},
 	}
 
@@ -183,6 +184,10 @@ func newImporter() importer {
 			standard: importList{
 				`"database/sql"`,
 				`"fmt"`,
+				`"reflect"`,
+				`"strconv"`,
+				`"strings"`,
+				`"time"`,
 			},
 			thirdParty: importList{
 				`"github.com/lbryio/sqlboiler/boil"`,
@@ -190,6 +195,7 @@ func newImporter() importer {
 				`"github.com/lbryio/sqlboiler/queries/qm"`,
 				`"github.com/lbryio/sqlboiler/strmangle"`,
 				`"github.com/pkg/errors"`,
+				`"github.com/lbryio/null.go"`,
 			},
 		},
 		"boil_types": {
@@ -315,55 +321,55 @@ func newImporter() importer {
 	// TranslateColumnType to see the type assignments.
 	imp.BasedOnType = mapImports{
 		"null.Float32": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Float64": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Int": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Int8": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Int16": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Int32": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Int64": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Uint": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Uint8": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Uint16": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Uint32": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Uint64": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.String": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Bool": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Time": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.JSON": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"null.Bytes": {
-			thirdParty: importList{`"gopkg.in/nullbio/null.v6"`},
+			thirdParty: importList{`"github.com/lbryio/null.go"`},
 		},
 		"time.Time": {
 			standard: importList{`"time"`},
diff --git a/boilingcore/imports_test.go b/boilingcore/imports_test.go
index ff2362d..b25eece 100644
--- a/boilingcore/imports_test.go
+++ b/boilingcore/imports_test.go
@@ -246,7 +246,7 @@ func TestCombineTypeImports(t *testing.T) {
 		},
 		thirdParty: importList{
 			`"github.com/lbryio/sqlboiler/boil"`,
-			`"gopkg.in/nullbio/null.v6"`,
+			`"github.com/lbryio/null.go"`,
 		},
 	}
 
@@ -281,7 +281,7 @@ func TestCombineTypeImports(t *testing.T) {
 		},
 		thirdParty: importList{
 			`"github.com/lbryio/sqlboiler/boil"`,
-			`"gopkg.in/nullbio/null.v6"`,
+			`"github.com/lbryio/null.go"`,
 		},
 	}
 
@@ -297,7 +297,7 @@ func TestCombineImports(t *testing.T) {
 
 	a := imports{
 		standard:   importList{"fmt"},
-		thirdParty: importList{"github.com/lbryio/sqlboiler", "gopkg.in/nullbio/null.v6"},
+		thirdParty: importList{"github.com/lbryio/sqlboiler", "github.com/lbryio/null.go"},
 	}
 	b := imports{
 		standard:   importList{"os"},
@@ -309,8 +309,8 @@ func TestCombineImports(t *testing.T) {
 	if c.standard[0] != "fmt" && c.standard[1] != "os" {
 		t.Errorf("Wanted: fmt, os got: %#v", c.standard)
 	}
-	if c.thirdParty[0] != "github.com/lbryio/sqlboiler" && c.thirdParty[1] != "gopkg.in/nullbio/null.v6" {
-		t.Errorf("Wanted: github.com/lbryio/sqlboiler, gopkg.in/nullbio/null.v6 got: %#v", c.thirdParty)
+	if c.thirdParty[0] != "github.com/lbryio/sqlboiler" && c.thirdParty[1] != "github.com/lbryio/null.go" {
+		t.Errorf("Wanted: github.com/lbryio/sqlboiler, github.com/lbryio/null.go got: %#v", c.thirdParty)
 	}
 }
 
diff --git a/queries/helpers_test.go b/queries/helpers_test.go
index d37fcd9..ab4b4ac 100644
--- a/queries/helpers_test.go
+++ b/queries/helpers_test.go
@@ -5,7 +5,7 @@ import (
 	"testing"
 	"time"
 
-	null "gopkg.in/nullbio/null.v6"
+	null "github.com/lbryio/null.go"
 )
 
 type testObj struct {
diff --git a/queries/query.go b/queries/query.go
index be539e5..b3ff830 100644
--- a/queries/query.go
+++ b/queries/query.go
@@ -3,8 +3,15 @@ package queries
 import (
 	"database/sql"
 	"fmt"
+	"reflect"
+	"strconv"
+	"strings"
+	"time"
 
+	"github.com/lbryio/null.go"
 	"github.com/lbryio/sqlboiler/boil"
+
+	"github.com/go-errors/errors"
 )
 
 // joinKind is the type of join
@@ -105,8 +112,11 @@ func RawG(query string, args ...interface{}) *Query {
 func (q *Query) Exec() (sql.Result, error) {
 	qs, args := buildQuery(q)
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, qs)
-		fmt.Fprintln(boil.DebugWriter, args)
+		qStr, err := interpolateParams(qs, args...)
+		if err != nil {
+			return nil, err
+		}
+		fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 	return q.executor.Exec(qs, args...)
 }
@@ -115,8 +125,11 @@ func (q *Query) Exec() (sql.Result, error) {
 func (q *Query) QueryRow() *sql.Row {
 	qs, args := buildQuery(q)
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, qs)
-		fmt.Fprintln(boil.DebugWriter, args)
+		qStr, err := interpolateParams(qs, args...)
+		if err != nil {
+			panic(err)
+		}
+		fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 	return q.executor.QueryRow(qs, args...)
 }
@@ -125,8 +138,11 @@ func (q *Query) QueryRow() *sql.Row {
 func (q *Query) Query() (*sql.Rows, error) {
 	qs, args := buildQuery(q)
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, qs)
-		fmt.Fprintln(boil.DebugWriter, args)
+		qStr, err := interpolateParams(qs, args...)
+		if err != nil {
+			return nil, err
+		}
+		fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 	return q.executor.Query(qs, args...)
 }
@@ -280,3 +296,69 @@ func AppendGroupBy(q *Query, clause string) {
 func AppendOrderBy(q *Query, clause string) {
 	q.orderBy = append(q.orderBy, clause)
 }
+
+// duplicated in boil_queries.tpl
+func interpolateParams(query string, args ...interface{}) (string, error) {
+	for i := 0; i < len(args); i++ {
+		field := reflect.ValueOf(args[i])
+
+		if value, ok := field.Interface().(time.Time); ok {
+			query = strings.Replace(query, "?", `"`+value.Format("2006-01-02 15:04:05")+`"`, 1)
+		} else if nullable, ok := field.Interface().(null.Nullable); ok {
+			if nullable.IsNull() {
+				query = strings.Replace(query, "?", "NULL", 1)
+			} else {
+				switch field.Type() {
+				case reflect.TypeOf(null.Time{}):
+					query = strings.Replace(query, "?", `"`+field.Interface().(null.Time).Time.Format("2006-01-02 15:04:05")+`"`, 1)
+				case reflect.TypeOf(null.Int{}):
+					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int).Int), 10), 1)
+				case reflect.TypeOf(null.Int8{}):
+					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int8).Int8), 10), 1)
+				case reflect.TypeOf(null.Int16{}):
+					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int16).Int16), 10), 1)
+				case reflect.TypeOf(null.Int32{}):
+					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int32).Int32), 10), 1)
+				case reflect.TypeOf(null.Int64{}):
+					query = strings.Replace(query, "?", strconv.FormatInt(field.Interface().(null.Int64).Int64, 10), 1)
+				case reflect.TypeOf(null.Uint{}):
+					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint).Uint), 10), 1)
+				case reflect.TypeOf(null.Uint8{}):
+					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint8).Uint8), 10), 1)
+				case reflect.TypeOf(null.Uint16{}):
+					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint16).Uint16), 10), 1)
+				case reflect.TypeOf(null.Uint32{}):
+					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint32).Uint32), 10), 1)
+				case reflect.TypeOf(null.Uint64{}):
+					query = strings.Replace(query, "?", strconv.FormatUint(field.Interface().(null.Uint64).Uint64, 10), 1)
+				case reflect.TypeOf(null.String{}):
+					query = strings.Replace(query, "?", `"`+field.Interface().(null.String).String+`"`, 1)
+				case reflect.TypeOf(null.Bool{}):
+					if field.Interface().(null.Bool).Bool {
+						query = strings.Replace(query, "?", "1", 1)
+					} else {
+						query = strings.Replace(query, "?", "0", 1)
+					}
+				}
+			}
+		} else {
+			switch field.Kind() {
+			case reflect.Bool:
+				boolString := "0"
+				if field.Bool() {
+					boolString = "1"
+				}
+				query = strings.Replace(query, "?", boolString, 1)
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				query = strings.Replace(query, "?", strconv.FormatInt(field.Int(), 10), 1)
+			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+				query = strings.Replace(query, "?", strconv.FormatUint(field.Uint(), 10), 1)
+			case reflect.String:
+				query = strings.Replace(query, "?", `"`+field.String()+`"`, 1)
+			default:
+				return "", errors.New("Dont know how to interpolate type " + field.Type().String())
+			}
+		}
+	}
+	return query, nil
+}
diff --git a/randomize/randomize.go b/randomize/randomize.go
index ea99c43..8deb88d 100644
--- a/randomize/randomize.go
+++ b/randomize/randomize.go
@@ -14,7 +14,7 @@ import (
 	"sync/atomic"
 	"time"
 
-	null "gopkg.in/nullbio/null.v6"
+	null "github.com/lbryio/null.go"
 
 	"github.com/pkg/errors"
 	"github.com/satori/go.uuid"
diff --git a/randomize/randomize_test.go b/randomize/randomize_test.go
index 6f117b7..ccef115 100644
--- a/randomize/randomize_test.go
+++ b/randomize/randomize_test.go
@@ -5,7 +5,7 @@ import (
 	"testing"
 	"time"
 
-	null "gopkg.in/nullbio/null.v6"
+	null "github.com/lbryio/null.go"
 )
 
 func TestRandomizeStruct(t *testing.T) {
diff --git a/templates/07_relationship_to_one_eager.tpl b/templates/07_relationship_to_one_eager.tpl
index 3b24f1a..3bf42f4 100644
--- a/templates/07_relationship_to_one_eager.tpl
+++ b/templates/07_relationship_to_one_eager.tpl
@@ -40,7 +40,11 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 	)
 
 	if boil.DebugMode {
-		fmt.Fprintf(boil.DebugWriter, "%s\n%v\n", query, args)
+    qStr, err := interpolateParams(query, args...)
+    if err != nil {
+      return err
+    }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	results, err := e.Query(query, args...)
diff --git a/templates/08_relationship_one_to_one_eager.tpl b/templates/08_relationship_one_to_one_eager.tpl
index 37d1af0..1fbf5f7 100644
--- a/templates/08_relationship_one_to_one_eager.tpl
+++ b/templates/08_relationship_one_to_one_eager.tpl
@@ -40,7 +40,11 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 	)
 
 	if boil.DebugMode {
-		fmt.Fprintf(boil.DebugWriter, "%s\n%v\n", query, args)
+    qStr, err := interpolateParams(query, args...)
+    if err != nil {
+      return err
+    }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	results, err := e.Query(query, args...)
diff --git a/templates/09_relationship_to_many_eager.tpl b/templates/09_relationship_to_many_eager.tpl
index 1603188..3ec5bf9 100644
--- a/templates/09_relationship_to_many_eager.tpl
+++ b/templates/09_relationship_to_many_eager.tpl
@@ -49,7 +49,11 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 		{{end -}}
 
 	if boil.DebugMode {
-		fmt.Fprintf(boil.DebugWriter, "%s\n%v\n", query, args)
+    qStr, err := interpolateParams(query, args...)
+    if err != nil {
+      return err
+    }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	results, err := e.Query(query, args...)
diff --git a/templates/10_relationship_to_one_setops.tpl b/templates/10_relationship_to_one_setops.tpl
index 14f726e..b293b48 100644
--- a/templates/10_relationship_to_one_setops.tpl
+++ b/templates/10_relationship_to_one_setops.tpl
@@ -53,8 +53,11 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 	values := []interface{}{related.{{$txt.ForeignTable.ColumnNameGo}}, o.{{$dot.Table.PKey.Columns | stringMap $dot.StringFuncs.titleCase | join ", o."}}{{"}"}}
 
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, updateQuery)
-		fmt.Fprintln(boil.DebugWriter, values)
+    qStr, err := interpolateParams(updateQuery, values...)
+    if err != nil {
+      return err
+    }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	if _, err = exec.Exec(updateQuery, values...); err != nil {
diff --git a/templates/11_relationship_one_to_one_setops.tpl b/templates/11_relationship_one_to_one_setops.tpl
index 826eec2..d4583ca 100644
--- a/templates/11_relationship_one_to_one_setops.tpl
+++ b/templates/11_relationship_one_to_one_setops.tpl
@@ -59,8 +59,11 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 		values := []interface{}{o.{{$txt.LocalTable.ColumnNameGo}}, related.{{$foreignPKeyCols | stringMap $dot.StringFuncs.titleCase | join ", related."}}{{"}"}}
 
 		if boil.DebugMode {
-			fmt.Fprintln(boil.DebugWriter, updateQuery)
-			fmt.Fprintln(boil.DebugWriter, values)
+      qStr, err := interpolateParams(updateQuery, values...)
+      if err != nil {
+        return err
+      }
+      fmt.Fprintln(boil.DebugWriter, qStr)
 		}
 
 		if _, err = exec.Exec(updateQuery, values...); err != nil {
diff --git a/templates/12_relationship_to_many_setops.tpl b/templates/12_relationship_to_many_setops.tpl
index 06159ee..35a4bd4 100644
--- a/templates/12_relationship_to_many_setops.tpl
+++ b/templates/12_relationship_to_many_setops.tpl
@@ -66,8 +66,11 @@ func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}(exec boil.Executo
 			values := []interface{}{o.{{$txt.LocalTable.ColumnNameGo}}, rel.{{$foreignPKeyCols | stringMap $dot.StringFuncs.titleCase | join ", rel."}}{{"}"}}
 
 			if boil.DebugMode {
-				fmt.Fprintln(boil.DebugWriter, updateQuery)
-				fmt.Fprintln(boil.DebugWriter, values)
+        qStr, err := interpolateParams(updateQuery, values...)
+        if err != nil {
+          return err
+        }
+        fmt.Fprintln(boil.DebugWriter, qStr)
 			}
 
 			if _, err = exec.Exec(updateQuery, values...); err != nil {
@@ -87,8 +90,11 @@ func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}(exec boil.Executo
 		values := []interface{}{{"{"}}o.{{$txt.LocalTable.ColumnNameGo}}, rel.{{$txt.ForeignTable.ColumnNameGo}}}
 
 		if boil.DebugMode {
-			fmt.Fprintln(boil.DebugWriter, query)
-			fmt.Fprintln(boil.DebugWriter, values)
+      qStr, err := interpolateParams(query, values...)
+      if err != nil {
+        return err
+      }
+      fmt.Fprintln(boil.DebugWriter, qStr)
 		}
 
 		_, err = exec.Exec(query, values...)
@@ -184,8 +190,11 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 	values := []interface{}{{"{"}}o.{{$txt.LocalTable.ColumnNameGo}}}
 	{{end -}}
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, query)
-		fmt.Fprintln(boil.DebugWriter, values)
+    qStr, err := interpolateParams(query, values...)
+    if err != nil {
+      return err
+    }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	_, err := exec.Exec(query, values...)
@@ -260,8 +269,11 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}(exec boil.Exec
 	}
 
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, query)
-		fmt.Fprintln(boil.DebugWriter, values)
+    qStr, err := interpolateParams(query, values...)
+    if err != nil {
+      return err
+    }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	_, err = exec.Exec(query, values...)
diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index 870e20d..8cd30b9 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -98,8 +98,11 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 	vals := queries.ValuesFromMapping(value, cache.valueMapping)
 
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, cache.query)
-		fmt.Fprintln(boil.DebugWriter, vals)
+	  qStr, err := interpolateParams(cache.query, vals...)
+	  if err != nil {
+	    return err
+	  }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	{{if .UseLastInsertID -}}
@@ -144,8 +147,11 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 	}
 
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, cache.retQuery)
-		fmt.Fprintln(boil.DebugWriter, identifierCols...)
+	  qStr, err := interpolateParams(cache.retQuery, identifierCols...)
+	  if err != nil {
+	    return err
+	  }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	err = exec.QueryRow(cache.retQuery, identifierCols...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...)
diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index bc4a6f5..1ac460b 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -78,8 +78,11 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 	values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping)
 
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, cache.query)
-		fmt.Fprintln(boil.DebugWriter, values)
+	  qStr, err := interpolateParams(cache.query, values...)
+	  if err != nil {
+	    return err
+	  }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	_, err = exec.Exec(cache.query, values...)
@@ -170,8 +173,11 @@ func (o {{$tableNameSingular}}Slice) UpdateAll(exec boil.Executor, cols M) error
 		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), {{if .Dialect.IndexPlaceholders}}len(colNames)+1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns, len(o)))
 
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, sql)
-		fmt.Fprintln(boil.DebugWriter, args...)
+	  qStr, err := interpolateParams(sql, args...)
+	  if err != nil {
+	    return err
+	  }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	_, err := exec.Exec(sql, args...)
diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index dbce58c..5cf6a14 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -147,8 +147,11 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 	}
 
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, cache.query)
-		fmt.Fprintln(boil.DebugWriter, vals)
+	  qStr, err := interpolateParams(cache.query, vals...)
+	  if err != nil {
+	    return err
+	  }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	{{if .UseLastInsertID -}}
@@ -193,8 +196,11 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 	}
 
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, cache.retQuery)
-		fmt.Fprintln(boil.DebugWriter, identifierCols...)
+	  qStr, err := interpolateParams(cache.retQuery, identifierCols...)
+	  if err != nil {
+	    return err
+	  }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	err = exec.QueryRow(cache.retQuery, identifierCols...).Scan(returns...)
diff --git a/templates/18_delete.tpl b/templates/18_delete.tpl
index e9a5177..20e819a 100644
--- a/templates/18_delete.tpl
+++ b/templates/18_delete.tpl
@@ -6,7 +6,7 @@
 // Panics on error.
 func (o *{{$tableNameSingular}}) DeleteP(exec boil.Executor) {
 	if err := o.Delete(exec); err != nil {
-	panic(boil.WrapErr(err))
+	  panic(boil.WrapErr(err))
 	}
 }
 
@@ -14,7 +14,7 @@ func (o *{{$tableNameSingular}}) DeleteP(exec boil.Executor) {
 // DeleteG will match against the primary key column to find the record to delete.
 func (o *{{$tableNameSingular}}) DeleteG() error {
 	if o == nil {
-	return errors.New("{{.PkgName}}: no {{$tableNameSingular}} provided for deletion")
+	  return errors.New("{{.PkgName}}: no {{$tableNameSingular}} provided for deletion")
 	}
 
 	return o.Delete(boil.GetDB())
@@ -25,7 +25,7 @@ func (o *{{$tableNameSingular}}) DeleteG() error {
 // Panics on error.
 func (o *{{$tableNameSingular}}) DeleteGP() {
 	if err := o.DeleteG(); err != nil {
-	panic(boil.WrapErr(err))
+	  panic(boil.WrapErr(err))
 	}
 }
 
@@ -33,12 +33,12 @@ func (o *{{$tableNameSingular}}) DeleteGP() {
 // Delete will match against the primary key column to find the record to delete.
 func (o *{{$tableNameSingular}}) Delete(exec boil.Executor) error {
 	if o == nil {
-	return errors.New("{{.PkgName}}: no {{$tableNameSingular}} provided for delete")
+	  return errors.New("{{.PkgName}}: no {{$tableNameSingular}} provided for delete")
 	}
 
 	{{if not .NoHooks -}}
 	if err := o.doBeforeDeleteHooks(exec); err != nil {
-	return err
+	  return err
 	}
 	{{- end}}
 
@@ -46,18 +46,21 @@ func (o *{{$tableNameSingular}}) Delete(exec boil.Executor) error {
 	sql := "DELETE FROM {{$schemaTable}} WHERE {{if .Dialect.IndexPlaceholders}}{{whereClause .LQ .RQ 1 .Table.PKey.Columns}}{{else}}{{whereClause .LQ .RQ 0 .Table.PKey.Columns}}{{end}}"
 
 	if boil.DebugMode {
-	fmt.Fprintln(boil.DebugWriter, sql)
-	fmt.Fprintln(boil.DebugWriter, args...)
+	  qStr, err := interpolateParams(sql, args...)
+	  if err != nil {
+	    return err
+	  }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	_, err := exec.Exec(sql, args...)
 	if err != nil {
-	return errors.Wrap(err, "{{.PkgName}}: unable to delete from {{.Table.Name}}")
+  	return errors.Wrap(err, "{{.PkgName}}: unable to delete from {{.Table.Name}}")
 	}
 
 	{{if not .NoHooks -}}
 	if err := o.doAfterDeleteHooks(exec); err != nil {
-	return err
+	  return err
 	}
 	{{- end}}
 
@@ -67,21 +70,21 @@ func (o *{{$tableNameSingular}}) Delete(exec boil.Executor) error {
 // DeleteAllP deletes all rows, and panics on error.
 func (q {{$tableNameSingular}}Query) DeleteAllP() {
 	if err := q.DeleteAll(); err != nil {
-	panic(boil.WrapErr(err))
+	  panic(boil.WrapErr(err))
 	}
 }
 
 // DeleteAll deletes all matching rows.
 func (q {{$tableNameSingular}}Query) DeleteAll() error {
 	if q.Query == nil {
-	return errors.New("{{.PkgName}}: no {{$tableNameSingular}}Query provided for delete all")
+	  return errors.New("{{.PkgName}}: no {{$tableNameSingular}}Query provided for delete all")
 	}
 
 	queries.SetDelete(q.Query)
 
 	_, err := q.Query.Exec()
 	if err != nil {
-	return errors.Wrap(err, "{{.PkgName}}: unable to delete all from {{.Table.Name}}")
+	  return errors.Wrap(err, "{{.PkgName}}: unable to delete all from {{.Table.Name}}")
 	}
 
 	return nil
@@ -90,14 +93,14 @@ func (q {{$tableNameSingular}}Query) DeleteAll() error {
 // DeleteAllGP deletes all rows in the slice, and panics on error.
 func (o {{$tableNameSingular}}Slice) DeleteAllGP() {
 	if err := o.DeleteAllG(); err != nil {
-	panic(boil.WrapErr(err))
+	  panic(boil.WrapErr(err))
 	}
 }
 
 // DeleteAllG deletes all rows in the slice.
 func (o {{$tableNameSingular}}Slice) DeleteAllG() error {
 	if o == nil {
-	return errors.New("{{.PkgName}}: no {{$tableNameSingular}} slice provided for delete all")
+	  return errors.New("{{.PkgName}}: no {{$tableNameSingular}} slice provided for delete all")
 	}
 	return o.DeleteAll(boil.GetDB())
 }
@@ -105,7 +108,7 @@ func (o {{$tableNameSingular}}Slice) DeleteAllG() error {
 // DeleteAllP deletes all rows in the slice, using an executor, and panics on error.
 func (o {{$tableNameSingular}}Slice) DeleteAllP(exec boil.Executor) {
 	if err := o.DeleteAll(exec); err != nil {
-	panic(boil.WrapErr(err))
+	  panic(boil.WrapErr(err))
 	}
 }
 
@@ -139,8 +142,11 @@ func (o {{$tableNameSingular}}Slice) DeleteAll(exec boil.Executor) error {
 		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns, len(o))
 
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, sql)
-		fmt.Fprintln(boil.DebugWriter, args)
+	  qStr, err := interpolateParams(sql, args...)
+	  if err != nil {
+	    return err
+	  }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	_, err := exec.Exec(sql, args...)
diff --git a/templates/20_exists.tpl b/templates/20_exists.tpl
index 2e20fa6..4c4031a 100644
--- a/templates/20_exists.tpl
+++ b/templates/20_exists.tpl
@@ -14,8 +14,11 @@ func {{$tableNameSingular}}Exists(exec boil.Executor, {{$pkArgs}}) (bool, error)
 	{{- end}}
 
 	if boil.DebugMode {
-		fmt.Fprintln(boil.DebugWriter, sql)
-		fmt.Fprintln(boil.DebugWriter, {{$pkNames | join ", "}})
+	  qStr, err := interpolateParams(sql, {{$pkNames | join ", "}})
+	  if err != nil {
+	    return false, err
+	  }
+    fmt.Fprintln(boil.DebugWriter, qStr)
 	}
 
 	row := exec.QueryRow(sql, {{$pkNames | join ", "}})
diff --git a/templates/22_query.tpl b/templates/22_query.tpl
index 512c717..2dcf973 100644
--- a/templates/22_query.tpl
+++ b/templates/22_query.tpl
@@ -16,7 +16,7 @@ func (q *{{$tableNameSingular}}Query) Where(filters {{$tableNameSingular}}Filter
 	for i := 0; i < r.NumField(); i++ {
 		f := r.Field(i)
 		if f.Elem().IsValid() {
-			if nullable, ok := f.Elem().Interface().(Nullable); ok && nullable.IsZero() {
+			if nullable, ok := f.Elem().Interface().(null.Nullable); ok && nullable.IsNull() {
 				queries.AppendWhere(q.Query, r.Type().Field(i).Tag.Get("boil")+" IS NULL")
 			} else {
 				queries.AppendWhere(q.Query, r.Type().Field(i).Tag.Get("boil")+" = ?", f.Elem().Interface())
diff --git a/templates/23_merge.tpl b/templates/23_merge.tpl
index 35ca404..6b5cdd2 100644
--- a/templates/23_merge.tpl
+++ b/templates/23_merge.tpl
@@ -72,7 +72,7 @@ func Merge{{$tableNamePlural}}(exec boil.Executor, primaryID uint64, secondaryID
 		pf := pr.Elem().Field(i)
 		sf := sr.Elem().Field(i)
 		if sf.IsValid() {
-			if nullable, ok := sf.Interface().(Nullable); ok && !nullable.IsZero() && pf.Interface().(Nullable).IsZero() {
+			if nullable, ok := sf.Interface().(null.Nullable); ok && !nullable.IsNull() && pf.Interface().(null.Nullable).IsNull() {
 				pf.Set(sf)
 			}
 		}
diff --git a/templates/singleton/boil_queries.tpl b/templates/singleton/boil_queries.tpl
index 248fae1..11f103b 100644
--- a/templates/singleton/boil_queries.tpl
+++ b/templates/singleton/boil_queries.tpl
@@ -136,3 +136,69 @@ func checkMerge(tx *sql.Tx, foreignKeys []foreignKey) error {
 
 	return nil
 }
+
+// duplicated in queries/query.go
+func interpolateParams(query string, args ...interface{}) (string, error) {
+	for i := 0; i < len(args); i++ {
+		field := reflect.ValueOf(args[i])
+
+		if value, ok := field.Interface().(time.Time); ok {
+			query = strings.Replace(query, "?", `"`+value.Format("2006-01-02 15:04:05")+`"`, 1)
+		} else if nullable, ok := field.Interface().(null.Nullable); ok {
+			if nullable.IsNull() {
+				query = strings.Replace(query, "?", "NULL", 1)
+			} else {
+				switch field.Type() {
+				case reflect.TypeOf(null.Time{}):
+					query = strings.Replace(query, "?", `"`+field.Interface().(null.Time).Time.Format("2006-01-02 15:04:05")+`"`, 1)
+				case reflect.TypeOf(null.Int{}):
+					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int).Int), 10), 1)
+				case reflect.TypeOf(null.Int8{}):
+					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int8).Int8), 10), 1)
+				case reflect.TypeOf(null.Int16{}):
+					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int16).Int16), 10), 1)
+				case reflect.TypeOf(null.Int32{}):
+					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int32).Int32), 10), 1)
+				case reflect.TypeOf(null.Int64{}):
+					query = strings.Replace(query, "?", strconv.FormatInt(field.Interface().(null.Int64).Int64, 10), 1)
+				case reflect.TypeOf(null.Uint{}):
+					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint).Uint), 10), 1)
+				case reflect.TypeOf(null.Uint8{}):
+					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint8).Uint8), 10), 1)
+				case reflect.TypeOf(null.Uint16{}):
+					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint16).Uint16), 10), 1)
+				case reflect.TypeOf(null.Uint32{}):
+					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint32).Uint32), 10), 1)
+				case reflect.TypeOf(null.Uint64{}):
+					query = strings.Replace(query, "?", strconv.FormatUint(field.Interface().(null.Uint64).Uint64, 10), 1)
+				case reflect.TypeOf(null.String{}):
+					query = strings.Replace(query, "?", `"`+field.Interface().(null.String).String+`"`, 1)
+				case reflect.TypeOf(null.Bool{}):
+					if field.Interface().(null.Bool).Bool {
+						query = strings.Replace(query, "?", "1", 1)
+					} else {
+						query = strings.Replace(query, "?", "0", 1)
+					}
+				}
+			}
+		} else {
+			switch field.Kind() {
+			case reflect.Bool:
+				boolString := "0"
+				if field.Bool() {
+					boolString = "1"
+				}
+				query = strings.Replace(query, "?", boolString, 1)
+			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+				query = strings.Replace(query, "?", strconv.FormatInt(field.Int(), 10), 1)
+			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+				query = strings.Replace(query, "?", strconv.FormatUint(field.Uint(), 10), 1)
+			case reflect.String:
+				query = strings.Replace(query, "?", `"`+field.String()+`"`, 1)
+			default:
+				return "", errors.New("Dont know how to interpolate type " + field.Type().String())
+			}
+		}
+	}
+	return query, nil
+}
diff --git a/templates/singleton/boil_types.tpl b/templates/singleton/boil_types.tpl
index aa61bf9..547d05d 100644
--- a/templates/singleton/boil_types.tpl
+++ b/templates/singleton/boil_types.tpl
@@ -1,11 +1,6 @@
 // M type is for providing columns and column values to UpdateAll.
 type M map[string]interface{}
 
-// Nullable means the value may represent an sql NULL. It is implemented by null.* types.
-type Nullable interface {
-	IsZero() bool
-}
-
 // foreignKey connects two tables. When merging records, foreign keys from secondary record must
 // be reassigned to primary record.
 type foreignKey struct {

From 9c8262b702a2224d7e437b2e9a405fc698db506d Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Thu, 20 Jul 2017 10:50:55 -0400
Subject: [PATCH 154/179] fix exists() finisher

---
 templates/03_finishers.tpl | 1 +
 1 file changed, 1 insertion(+)

diff --git a/templates/03_finishers.tpl b/templates/03_finishers.tpl
index 13ea14d..df2081d 100644
--- a/templates/03_finishers.tpl
+++ b/templates/03_finishers.tpl
@@ -105,6 +105,7 @@ func (q {{$tableNameSingular}}Query) Exists() (bool, error) {
 	var count int64
 
 	queries.SetCount(q.Query)
+	queries.SetSelect(q.Query, []string{})
 	queries.SetLimit(q.Query, 1)
 
 	err := q.Query.QueryRow().Scan(&count)

From 99a3a1d091d13401cd635e9b376ffec8f72ef156 Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Tue, 1 Aug 2017 13:00:14 -0400
Subject: [PATCH 155/179] make merge compatible with an existing transaction

---
 templates/23_merge.tpl | 47 ++++++++++++++++++++++++++----------------
 1 file changed, 29 insertions(+), 18 deletions(-)

diff --git a/templates/23_merge.tpl b/templates/23_merge.tpl
index 6b5cdd2..d84ed28 100644
--- a/templates/23_merge.tpl
+++ b/templates/23_merge.tpl
@@ -4,32 +4,42 @@
 {{- else -}}
 	{{- $dot := . }}
 // Merge combines two {{$tableNamePlural}} into one. The primary record will be kept, and the secondary will be deleted.
-func Merge{{$tableNamePlural}}(exec boil.Executor, primaryID uint64, secondaryID uint64) error {
-	txdb, ok := exec.(boil.Beginner)
+func Merge{{$tableNamePlural}}(exec boil.Executor, primaryID uint64, secondaryID uint64) (err error) {
+	tx, ok := exec.(boil.Transactor)
 	if !ok {
-		return errors.New("database does not support transactions")
-	}
+		txdb, ok := exec.(boil.Beginner)
+		if !ok {
+			return errors.New("database does not support transactions")
+		}
 
-	tx, txErr := txdb.Begin()
-	if txErr != nil {
-		return txErr
+		tx, err = txdb.Begin()
+		if err != nil {
+			return err
+		}
+
+		defer func() {
+			if p := recover(); p != nil {
+				tx.Rollback()
+				panic(p) // Rollback, then propagate panic
+			} else if err != nil {
+				tx.Rollback()
+			} else {
+				err = tx.Commit()
+			}
+		}()
 	}
 
   primary, err := Find{{$tableNameSingular}}(tx, primaryID)
   if err != nil {
-    tx.Rollback()
     return err
-  }
-	if primary == nil {
+  } else if primary == nil {
 		return errors.New("Primary {{$tableNameSingular}} not found")
 	}
 
   secondary, err := Find{{$tableNameSingular}}(tx, secondaryID)
   if err != nil {
-    tx.Rollback()
     return err
-  }
-	if secondary == nil {
+  } else if secondary == nil {
 		return errors.New("Secondary {{$tableNameSingular}} not found")
 	}
 
@@ -59,9 +69,13 @@ func Merge{{$tableNamePlural}}(exec boil.Executor, primaryID uint64, secondaryID
     {{- end }}
   }
 
-  err = mergeModels(tx, primaryID, secondaryID, foreignKeys, conflictingKeys)
+  sqlTx, ok := tx.(*sql.Tx)
+  if !ok {
+    return errors.New("tx must be an sql.Tx")
+  }
+
+  err = mergeModels(sqlTx, primaryID, secondaryID, foreignKeys, conflictingKeys)
   if err != nil {
-    tx.Rollback()
     return err
   }
 
@@ -80,17 +94,14 @@ func Merge{{$tableNamePlural}}(exec boil.Executor, primaryID uint64, secondaryID
 
 	err = primary.Update(tx)
 	if err != nil {
-		tx.Rollback()
 		return errors.WithStack(err)
 	}
 
 	err = secondary.Delete(tx)
 	if err != nil {
-		tx.Rollback()
 		return errors.WithStack(err)
 	}
 
-  tx.Commit()
   return nil
 }
 

From 23f245776de75c7d884a2f208702147c417376ea Mon Sep 17 00:00:00 2001
From: Guy Tish <guy@ziprecruiter.com>
Date: Mon, 26 Jun 2017 14:14:16 +0300
Subject: [PATCH 156/179] Added table columns and table names as anonymous
 struct

---
 templates/00_struct.tpl                  | 10 ++++++++++
 templates/singleton/boil_table_names.tpl |  9 +++++++++
 2 files changed, 19 insertions(+)
 create mode 100644 templates/singleton/boil_table_names.tpl

diff --git a/templates/00_struct.tpl b/templates/00_struct.tpl
index f9c3a04..a2608fa 100644
--- a/templates/00_struct.tpl
+++ b/templates/00_struct.tpl
@@ -17,6 +17,16 @@ type {{$modelName}} struct {
 	{{end -}}
 }
 
+var {{$modelName}}Columns = struct {
+	{{range $column := .Table.Columns -}}
+	{{titleCase $column.Name}} string
+	{{end -}}
+}{
+	{{range $column := .Table.Columns -}}
+	{{titleCase $column.Name}}: "{{$column.Name}}",
+	{{end -}}
+}
+
 // {{$modelName}}Filter allows you to filter on any columns by making them all pointers.
 type {{$modelName}}Filter struct {
 	{{range $column := .Table.Columns -}}
diff --git a/templates/singleton/boil_table_names.tpl b/templates/singleton/boil_table_names.tpl
new file mode 100644
index 0000000..062bcad
--- /dev/null
+++ b/templates/singleton/boil_table_names.tpl
@@ -0,0 +1,9 @@
+var TableNames = struct {
+	{{range $table := .Tables -}}
+	{{titleCase $table.Name}} string
+	{{end -}}
+}{
+	{{range $table := .Tables -}}
+	{{titleCase $table.Name}}: "{{$table.Name}}",
+	{{end -}}
+}

From e3398120275addca81260d0d541abb99f1fa0dae Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Sun, 4 Jun 2017 12:29:04 -0700
Subject: [PATCH 157/179] Stop using aliases in the relationship select

- This caused issues with mysql who doesn't understand the syntax:
  "delete from x as y where y.id = ?"
---
 templates/06_relationship_to_many.tpl | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/templates/06_relationship_to_many.tpl b/templates/06_relationship_to_many.tpl
index 10aa842..0e6e634 100644
--- a/templates/06_relationship_to_many.tpl
+++ b/templates/06_relationship_to_many.tpl
@@ -16,7 +16,7 @@ func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}G(mods ...qm.QueryMod
 {{- if not (eq $txt.Function.Name $txt.ForeignTable.NamePluralGo)}} via {{.ForeignColumn}} column{{- end}}.
 func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}(exec boil.Executor, mods ...qm.QueryMod) {{$tableNameSingular}}Query {
 	queryMods := []qm.QueryMod{
-		qm.Select("{{id 0 | $dot.Quotes}}.*"),
+		qm.Select("{{$schemaForeignTable}}.*"),
 	}
 
 	if len(mods) != 0 {
@@ -25,17 +25,18 @@ func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}(exec boil.Executor,
 
 		{{if .ToJoinTable -}}
 	queryMods = append(queryMods,
-		qm.InnerJoin("{{.JoinTable | $dot.SchemaTable}} as {{id 1 | $dot.Quotes}} on {{id 0 | $dot.Quotes}}.{{.ForeignColumn | $dot.Quotes}} = {{id 1 | $dot.Quotes}}.{{.JoinForeignColumn | $dot.Quotes}}"),
-		qm.Where("{{id 1 | $dot.Quotes}}.{{.JoinLocalColumn | $dot.Quotes}}=?", o.{{$txt.LocalTable.ColumnNameGo}}),
+		{{$schemaJoinTable := .JoinTable | $.SchemaTable -}}
+		qm.InnerJoin("{{$schemaJoinTable}} on {{$schemaForeignTable}}.{{.ForeignColumn | $dot.Quotes}} = {{$schemaJoinTable}}.{{.JoinForeignColumn | $dot.Quotes}}"),
+		qm.Where("{{$schemaJoinTable}}.{{.JoinLocalColumn | $dot.Quotes}}=?", o.{{$txt.LocalTable.ColumnNameGo}}),
 	)
 		{{else -}}
 	queryMods = append(queryMods,
-		qm.Where("{{id 0 | $dot.Quotes}}.{{.ForeignColumn | $dot.Quotes}}=?", o.{{$txt.LocalTable.ColumnNameGo}}),
+		qm.Where("{{$schemaForeignTable}}.{{.ForeignColumn | $dot.Quotes}}=?", o.{{$txt.LocalTable.ColumnNameGo}}),
 	)
 		{{end}}
 
 	query := {{$txt.ForeignTable.NamePluralGo}}(exec, queryMods...)
-	queries.SetFrom(query.Query, "{{$schemaForeignTable}} as {{id 0 | $dot.Quotes}}")
+	queries.SetFrom(query.Query, "{{$schemaForeignTable}}")
 	return query
 }
 

From ca9f47de8bbab78e3401f818f965825da1425007 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Wed, 14 Jun 2017 21:14:54 -0700
Subject: [PATCH 158/179] Correct nullability for tests in to_one

- Use the nullability of the fkey column in question to determine
  nullability for the entire struct to make things easy, otherwise
  we'd have to pluck out one at a time. This makes the tests pass
  instead of fail sporadically.
- Fix #160
---
 templates_test/relationship_to_one.tpl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/templates_test/relationship_to_one.tpl b/templates_test/relationship_to_one.tpl
index e95c61a..9211284 100644
--- a/templates_test/relationship_to_one.tpl
+++ b/templates_test/relationship_to_one.tpl
@@ -13,10 +13,10 @@ func test{{$txt.LocalTable.NameGo}}ToOne{{$txt.ForeignTable.NameGo}}Using{{$txt.
 	var foreign {{$txt.ForeignTable.NameGo}}
 
 	seed := randomize.NewSeed()
-	if err := randomize.Struct(seed, &local, {{$varNameSingular}}DBTypes, true, {{$varNameSingular}}ColumnsWithDefault...); err != nil {
+	if err := randomize.Struct(seed, &local, {{$varNameSingular}}DBTypes, {{if .Nullable}}true{{else}}false{{end}}, {{$varNameSingular}}ColumnsWithDefault...); err != nil {
 		t.Errorf("Unable to randomize {{$txt.LocalTable.NameGo}} struct: %s", err)
 	}
-	if err := randomize.Struct(seed, &foreign, {{$foreignVarNameSingular}}DBTypes, true, {{$foreignVarNameSingular}}ColumnsWithDefault...); err != nil {
+	if err := randomize.Struct(seed, &foreign, {{$foreignVarNameSingular}}DBTypes, {{if .ForeignColumnNullable}}true{{else}}false{{end}}, {{$foreignVarNameSingular}}ColumnsWithDefault...); err != nil {
 		t.Errorf("Unable to randomize {{$txt.ForeignTable.NameGo}} struct: %s", err)
 	}
 

From ce9d13abf0492b2bb473f3ee18c00ae7df9559b2 Mon Sep 17 00:00:00 2001
From: Aaron L <aaron@bettercoder.net>
Date: Sun, 2 Jul 2017 11:16:21 -0700
Subject: [PATCH 159/179] Fix hook documentation to include error return

Fix #171
---
 README.md | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 194fdd8..51b5fbe 100644
--- a/README.md
+++ b/README.md
@@ -956,15 +956,16 @@ it with the `AddModelHook` method. Here is an example of a before insert hook:
 
 ```go
 // Define my hook function
-func myHook(exec boil.Executor, p *Pilot) {
+func myHook(exec boil.Executor, p *Pilot) error {
   // Do stuff
+  return nil
 }
 
 // Register my before insert hook for pilots
 models.AddPilotHook(boil.BeforeInsertHook, myHook)
 ```
 
-Your `ModelHook` will always be defined as `func(boil.Executor, *Model)`
+Your `ModelHook` will always be defined as `func(boil.Executor, *Model) error`
 
 ### Transactions
 

From 8837a986eed7e8ddeae1784e14cdc622cbeb03f3 Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Wed, 23 Aug 2017 13:36:13 -0400
Subject: [PATCH 160/179] consistent order to unique key columns

---
 bdb/drivers/mysql.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go
index 41510ee..431bad1 100644
--- a/bdb/drivers/mysql.go
+++ b/bdb/drivers/mysql.go
@@ -3,6 +3,7 @@ package drivers
 import (
 	"database/sql"
 	"fmt"
+	"sort"
 	"strconv"
 	"strings"
 
@@ -261,6 +262,7 @@ func (m *MySQLDriver) UniqueKeyInfo(schema, tableName string) ([]bdb.UniqueKey,
 		}
 
 		ukey.Columns = strings.Split(columns, ",")
+		sort.Strings(ukey.Columns)
 
 		ukeys = append(ukeys, ukey)
 	}

From 3abac13aeb644da942649b4338d290cfbf2b1227 Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Wed, 23 Aug 2017 16:37:33 -0400
Subject: [PATCH 161/179] export InterpolateParams

---
 templates/07_relationship_to_one_eager.tpl      | 2 +-
 templates/08_relationship_one_to_one_eager.tpl  | 2 +-
 templates/09_relationship_to_many_eager.tpl     | 2 +-
 templates/10_relationship_to_one_setops.tpl     | 2 +-
 templates/11_relationship_one_to_one_setops.tpl | 2 +-
 templates/12_relationship_to_many_setops.tpl    | 8 ++++----
 templates/15_insert.tpl                         | 4 ++--
 templates/16_update.tpl                         | 4 ++--
 templates/17_upsert.tpl                         | 4 ++--
 templates/18_delete.tpl                         | 4 ++--
 templates/20_exists.tpl                         | 2 +-
 templates/singleton/boil_queries.tpl            | 2 +-
 12 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/templates/07_relationship_to_one_eager.tpl b/templates/07_relationship_to_one_eager.tpl
index 3bf42f4..28010fd 100644
--- a/templates/07_relationship_to_one_eager.tpl
+++ b/templates/07_relationship_to_one_eager.tpl
@@ -40,7 +40,7 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 	)
 
 	if boil.DebugMode {
-    qStr, err := interpolateParams(query, args...)
+    qStr, err := InterpolateParams(query, args...)
     if err != nil {
       return err
     }
diff --git a/templates/08_relationship_one_to_one_eager.tpl b/templates/08_relationship_one_to_one_eager.tpl
index 1fbf5f7..261b30c 100644
--- a/templates/08_relationship_one_to_one_eager.tpl
+++ b/templates/08_relationship_one_to_one_eager.tpl
@@ -40,7 +40,7 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 	)
 
 	if boil.DebugMode {
-    qStr, err := interpolateParams(query, args...)
+    qStr, err := InterpolateParams(query, args...)
     if err != nil {
       return err
     }
diff --git a/templates/09_relationship_to_many_eager.tpl b/templates/09_relationship_to_many_eager.tpl
index 3ec5bf9..8c4159b 100644
--- a/templates/09_relationship_to_many_eager.tpl
+++ b/templates/09_relationship_to_many_eager.tpl
@@ -49,7 +49,7 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 		{{end -}}
 
 	if boil.DebugMode {
-    qStr, err := interpolateParams(query, args...)
+    qStr, err := InterpolateParams(query, args...)
     if err != nil {
       return err
     }
diff --git a/templates/10_relationship_to_one_setops.tpl b/templates/10_relationship_to_one_setops.tpl
index b293b48..8362420 100644
--- a/templates/10_relationship_to_one_setops.tpl
+++ b/templates/10_relationship_to_one_setops.tpl
@@ -53,7 +53,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 	values := []interface{}{related.{{$txt.ForeignTable.ColumnNameGo}}, o.{{$dot.Table.PKey.Columns | stringMap $dot.StringFuncs.titleCase | join ", o."}}{{"}"}}
 
 	if boil.DebugMode {
-    qStr, err := interpolateParams(updateQuery, values...)
+    qStr, err := InterpolateParams(updateQuery, values...)
     if err != nil {
       return err
     }
diff --git a/templates/11_relationship_one_to_one_setops.tpl b/templates/11_relationship_one_to_one_setops.tpl
index d4583ca..7648e23 100644
--- a/templates/11_relationship_one_to_one_setops.tpl
+++ b/templates/11_relationship_one_to_one_setops.tpl
@@ -59,7 +59,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 		values := []interface{}{o.{{$txt.LocalTable.ColumnNameGo}}, related.{{$foreignPKeyCols | stringMap $dot.StringFuncs.titleCase | join ", related."}}{{"}"}}
 
 		if boil.DebugMode {
-      qStr, err := interpolateParams(updateQuery, values...)
+      qStr, err := InterpolateParams(updateQuery, values...)
       if err != nil {
         return err
       }
diff --git a/templates/12_relationship_to_many_setops.tpl b/templates/12_relationship_to_many_setops.tpl
index 35a4bd4..6794889 100644
--- a/templates/12_relationship_to_many_setops.tpl
+++ b/templates/12_relationship_to_many_setops.tpl
@@ -66,7 +66,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}(exec boil.Executo
 			values := []interface{}{o.{{$txt.LocalTable.ColumnNameGo}}, rel.{{$foreignPKeyCols | stringMap $dot.StringFuncs.titleCase | join ", rel."}}{{"}"}}
 
 			if boil.DebugMode {
-        qStr, err := interpolateParams(updateQuery, values...)
+        qStr, err := InterpolateParams(updateQuery, values...)
         if err != nil {
           return err
         }
@@ -90,7 +90,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}(exec boil.Executo
 		values := []interface{}{{"{"}}o.{{$txt.LocalTable.ColumnNameGo}}, rel.{{$txt.ForeignTable.ColumnNameGo}}}
 
 		if boil.DebugMode {
-      qStr, err := interpolateParams(query, values...)
+      qStr, err := InterpolateParams(query, values...)
       if err != nil {
         return err
       }
@@ -190,7 +190,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 	values := []interface{}{{"{"}}o.{{$txt.LocalTable.ColumnNameGo}}}
 	{{end -}}
 	if boil.DebugMode {
-    qStr, err := interpolateParams(query, values...)
+    qStr, err := InterpolateParams(query, values...)
     if err != nil {
       return err
     }
@@ -269,7 +269,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}(exec boil.Exec
 	}
 
 	if boil.DebugMode {
-    qStr, err := interpolateParams(query, values...)
+    qStr, err := InterpolateParams(query, values...)
     if err != nil {
       return err
     }
diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index 8cd30b9..00b6f5b 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -98,7 +98,7 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 	vals := queries.ValuesFromMapping(value, cache.valueMapping)
 
 	if boil.DebugMode {
-	  qStr, err := interpolateParams(cache.query, vals...)
+	  qStr, err := InterpolateParams(cache.query, vals...)
 	  if err != nil {
 	    return err
 	  }
@@ -147,7 +147,7 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 	}
 
 	if boil.DebugMode {
-	  qStr, err := interpolateParams(cache.retQuery, identifierCols...)
+	  qStr, err := InterpolateParams(cache.retQuery, identifierCols...)
 	  if err != nil {
 	    return err
 	  }
diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index 1ac460b..1f67234 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -78,7 +78,7 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 	values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping)
 
 	if boil.DebugMode {
-	  qStr, err := interpolateParams(cache.query, values...)
+	  qStr, err := InterpolateParams(cache.query, values...)
 	  if err != nil {
 	    return err
 	  }
@@ -173,7 +173,7 @@ func (o {{$tableNameSingular}}Slice) UpdateAll(exec boil.Executor, cols M) error
 		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), {{if .Dialect.IndexPlaceholders}}len(colNames)+1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns, len(o)))
 
 	if boil.DebugMode {
-	  qStr, err := interpolateParams(sql, args...)
+	  qStr, err := InterpolateParams(sql, args...)
 	  if err != nil {
 	    return err
 	  }
diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index 5cf6a14..6eef9fe 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -147,7 +147,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 	}
 
 	if boil.DebugMode {
-	  qStr, err := interpolateParams(cache.query, vals...)
+	  qStr, err := InterpolateParams(cache.query, vals...)
 	  if err != nil {
 	    return err
 	  }
@@ -196,7 +196,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 	}
 
 	if boil.DebugMode {
-	  qStr, err := interpolateParams(cache.retQuery, identifierCols...)
+	  qStr, err := InterpolateParams(cache.retQuery, identifierCols...)
 	  if err != nil {
 	    return err
 	  }
diff --git a/templates/18_delete.tpl b/templates/18_delete.tpl
index 20e819a..8c63e43 100644
--- a/templates/18_delete.tpl
+++ b/templates/18_delete.tpl
@@ -46,7 +46,7 @@ func (o *{{$tableNameSingular}}) Delete(exec boil.Executor) error {
 	sql := "DELETE FROM {{$schemaTable}} WHERE {{if .Dialect.IndexPlaceholders}}{{whereClause .LQ .RQ 1 .Table.PKey.Columns}}{{else}}{{whereClause .LQ .RQ 0 .Table.PKey.Columns}}{{end}}"
 
 	if boil.DebugMode {
-	  qStr, err := interpolateParams(sql, args...)
+	  qStr, err := InterpolateParams(sql, args...)
 	  if err != nil {
 	    return err
 	  }
@@ -142,7 +142,7 @@ func (o {{$tableNameSingular}}Slice) DeleteAll(exec boil.Executor) error {
 		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns, len(o))
 
 	if boil.DebugMode {
-	  qStr, err := interpolateParams(sql, args...)
+	  qStr, err := InterpolateParams(sql, args...)
 	  if err != nil {
 	    return err
 	  }
diff --git a/templates/20_exists.tpl b/templates/20_exists.tpl
index 4c4031a..7d3dc3d 100644
--- a/templates/20_exists.tpl
+++ b/templates/20_exists.tpl
@@ -14,7 +14,7 @@ func {{$tableNameSingular}}Exists(exec boil.Executor, {{$pkArgs}}) (bool, error)
 	{{- end}}
 
 	if boil.DebugMode {
-	  qStr, err := interpolateParams(sql, {{$pkNames | join ", "}})
+	  qStr, err := InterpolateParams(sql, {{$pkNames | join ", "}})
 	  if err != nil {
 	    return false, err
 	  }
diff --git a/templates/singleton/boil_queries.tpl b/templates/singleton/boil_queries.tpl
index 11f103b..0d3c812 100644
--- a/templates/singleton/boil_queries.tpl
+++ b/templates/singleton/boil_queries.tpl
@@ -138,7 +138,7 @@ func checkMerge(tx *sql.Tx, foreignKeys []foreignKey) error {
 }
 
 // duplicated in queries/query.go
-func interpolateParams(query string, args ...interface{}) (string, error) {
+func InterpolateParams(query string, args ...interface{}) (string, error) {
 	for i := 0; i < len(args); i++ {
 		field := reflect.ValueOf(args[i])
 

From faec3464818e1429f49922dec917d7313235a40b Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Wed, 23 Aug 2017 16:59:29 -0400
Subject: [PATCH 162/179] use interface to enable custom Tx types

---
 boil/db.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/boil/db.go b/boil/db.go
index 84bc7d3..2d31d38 100644
--- a/boil/db.go
+++ b/boil/db.go
@@ -19,7 +19,7 @@ type Transactor interface {
 
 // Beginner begins transactions.
 type Beginner interface {
-	Begin() (*sql.Tx, error)
+	Begin() (Transactor, error)
 }
 
 // Begin a transaction

From 544ff7afdd48696d7659886fc9c3b0e45588fd5f Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Wed, 23 Aug 2017 17:03:24 -0400
Subject: [PATCH 163/179] typo

---
 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 431bad1..dec80e0 100644
--- a/bdb/drivers/mysql.go
+++ b/bdb/drivers/mysql.go
@@ -380,7 +380,7 @@ func (m *MySQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
 			if unsigned {
 				c.Type = "null.Uint64"
 			} else {
-				c.Type = "null.Uint64"
+				c.Type = "null.Int64"
 			}
 		case "float":
 			c.Type = "null.Float32"

From 55f42bc03809b788249594b190801485a236431b Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Thu, 24 Aug 2017 11:58:13 -0400
Subject: [PATCH 164/179] just use interfaces

---
 boilingcore/imports.go               | 1 -
 templates/23_merge.tpl               | 7 +------
 templates/singleton/boil_queries.tpl | 6 +++---
 3 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index 2c31c63..528a946 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -182,7 +182,6 @@ func newImporter() importer {
 	imp.Singleton = mapImports{
 		"boil_queries": imports{
 			standard: importList{
-				`"database/sql"`,
 				`"fmt"`,
 				`"reflect"`,
 				`"strconv"`,
diff --git a/templates/23_merge.tpl b/templates/23_merge.tpl
index d84ed28..9f1af10 100644
--- a/templates/23_merge.tpl
+++ b/templates/23_merge.tpl
@@ -69,12 +69,7 @@ func Merge{{$tableNamePlural}}(exec boil.Executor, primaryID uint64, secondaryID
     {{- end }}
   }
 
-  sqlTx, ok := tx.(*sql.Tx)
-  if !ok {
-    return errors.New("tx must be an sql.Tx")
-  }
-
-  err = mergeModels(sqlTx, primaryID, secondaryID, foreignKeys, conflictingKeys)
+  err = mergeModels(tx, primaryID, secondaryID, foreignKeys, conflictingKeys)
   if err != nil {
     return err
   }
diff --git a/templates/singleton/boil_queries.tpl b/templates/singleton/boil_queries.tpl
index 0d3c812..89b0e74 100644
--- a/templates/singleton/boil_queries.tpl
+++ b/templates/singleton/boil_queries.tpl
@@ -20,7 +20,7 @@ func NewQuery(exec boil.Executor, mods ...qm.QueryMod) *queries.Query {
 	return q
 }
 
-func mergeModels(tx *sql.Tx, primaryID uint64, secondaryID uint64, foreignKeys []foreignKey, conflictingKeys []conflictingUniqueKey) error {
+func mergeModels(tx boil.Executor, primaryID uint64, secondaryID uint64, foreignKeys []foreignKey, conflictingKeys []conflictingUniqueKey) error {
 	if len(foreignKeys) < 1 {
 		return nil
 	}
@@ -48,7 +48,7 @@ func mergeModels(tx *sql.Tx, primaryID uint64, secondaryID uint64, foreignKeys [
 	return checkMerge(tx, foreignKeys)
 }
 
-func deleteConflictsBeforeMerge(tx *sql.Tx, conflict conflictingUniqueKey, primaryID uint64, secondaryID uint64) error {
+func deleteConflictsBeforeMerge(tx boil.Executor, conflict conflictingUniqueKey, primaryID uint64, secondaryID uint64) error {
 	conflictingColumns := strmangle.SetComplement(conflict.columns, []string{conflict.objectIdColumn})
 
 	if len(conflictingColumns) < 1 {
@@ -98,7 +98,7 @@ func deleteConflictsBeforeMerge(tx *sql.Tx, conflict conflictingUniqueKey, prima
 	return nil
 }
 
-func checkMerge(tx *sql.Tx, foreignKeys []foreignKey) error {
+func checkMerge(tx boil.Executor, foreignKeys []foreignKey) error {
 	uniqueColumns := []interface{}{}
 	uniqueColumnNames := map[string]bool{}
 	handledTablesColumns := map[string]bool{}

From cd445bf2f42346ac3dd5a1398e1f3ccadbe902e8 Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Sat, 2 Sep 2017 11:27:27 -0400
Subject: [PATCH 165/179] revert interpolateParams, since we're doing our own
 logging now

---
 boilingcore/imports.go                        |  5 -
 queries/query.go                              | 94 ++-----------------
 templates/07_relationship_to_one_eager.tpl    |  6 +-
 .../08_relationship_one_to_one_eager.tpl      |  6 +-
 templates/09_relationship_to_many_eager.tpl   |  6 +-
 templates/10_relationship_to_one_setops.tpl   |  7 +-
 .../11_relationship_one_to_one_setops.tpl     |  7 +-
 templates/12_relationship_to_many_setops.tpl  | 28 ++----
 templates/15_insert.tpl                       | 14 +--
 templates/16_update.tpl                       | 14 +--
 templates/17_upsert.tpl                       | 14 +--
 templates/18_delete.tpl                       | 16 +---
 templates/20_exists.tpl                       |  7 +-
 templates/singleton/boil_queries.tpl          | 66 -------------
 14 files changed, 40 insertions(+), 250 deletions(-)

diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index 528a946..13ed119 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -183,10 +183,6 @@ func newImporter() importer {
 		"boil_queries": imports{
 			standard: importList{
 				`"fmt"`,
-				`"reflect"`,
-				`"strconv"`,
-				`"strings"`,
-				`"time"`,
 			},
 			thirdParty: importList{
 				`"github.com/lbryio/sqlboiler/boil"`,
@@ -194,7 +190,6 @@ func newImporter() importer {
 				`"github.com/lbryio/sqlboiler/queries/qm"`,
 				`"github.com/lbryio/sqlboiler/strmangle"`,
 				`"github.com/pkg/errors"`,
-				`"github.com/lbryio/null.go"`,
 			},
 		},
 		"boil_types": {
diff --git a/queries/query.go b/queries/query.go
index b3ff830..be539e5 100644
--- a/queries/query.go
+++ b/queries/query.go
@@ -3,15 +3,8 @@ package queries
 import (
 	"database/sql"
 	"fmt"
-	"reflect"
-	"strconv"
-	"strings"
-	"time"
 
-	"github.com/lbryio/null.go"
 	"github.com/lbryio/sqlboiler/boil"
-
-	"github.com/go-errors/errors"
 )
 
 // joinKind is the type of join
@@ -112,11 +105,8 @@ func RawG(query string, args ...interface{}) *Query {
 func (q *Query) Exec() (sql.Result, error) {
 	qs, args := buildQuery(q)
 	if boil.DebugMode {
-		qStr, err := interpolateParams(qs, args...)
-		if err != nil {
-			return nil, err
-		}
-		fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, qs)
+		fmt.Fprintln(boil.DebugWriter, args)
 	}
 	return q.executor.Exec(qs, args...)
 }
@@ -125,11 +115,8 @@ func (q *Query) Exec() (sql.Result, error) {
 func (q *Query) QueryRow() *sql.Row {
 	qs, args := buildQuery(q)
 	if boil.DebugMode {
-		qStr, err := interpolateParams(qs, args...)
-		if err != nil {
-			panic(err)
-		}
-		fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, qs)
+		fmt.Fprintln(boil.DebugWriter, args)
 	}
 	return q.executor.QueryRow(qs, args...)
 }
@@ -138,11 +125,8 @@ func (q *Query) QueryRow() *sql.Row {
 func (q *Query) Query() (*sql.Rows, error) {
 	qs, args := buildQuery(q)
 	if boil.DebugMode {
-		qStr, err := interpolateParams(qs, args...)
-		if err != nil {
-			return nil, err
-		}
-		fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, qs)
+		fmt.Fprintln(boil.DebugWriter, args)
 	}
 	return q.executor.Query(qs, args...)
 }
@@ -296,69 +280,3 @@ func AppendGroupBy(q *Query, clause string) {
 func AppendOrderBy(q *Query, clause string) {
 	q.orderBy = append(q.orderBy, clause)
 }
-
-// duplicated in boil_queries.tpl
-func interpolateParams(query string, args ...interface{}) (string, error) {
-	for i := 0; i < len(args); i++ {
-		field := reflect.ValueOf(args[i])
-
-		if value, ok := field.Interface().(time.Time); ok {
-			query = strings.Replace(query, "?", `"`+value.Format("2006-01-02 15:04:05")+`"`, 1)
-		} else if nullable, ok := field.Interface().(null.Nullable); ok {
-			if nullable.IsNull() {
-				query = strings.Replace(query, "?", "NULL", 1)
-			} else {
-				switch field.Type() {
-				case reflect.TypeOf(null.Time{}):
-					query = strings.Replace(query, "?", `"`+field.Interface().(null.Time).Time.Format("2006-01-02 15:04:05")+`"`, 1)
-				case reflect.TypeOf(null.Int{}):
-					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int).Int), 10), 1)
-				case reflect.TypeOf(null.Int8{}):
-					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int8).Int8), 10), 1)
-				case reflect.TypeOf(null.Int16{}):
-					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int16).Int16), 10), 1)
-				case reflect.TypeOf(null.Int32{}):
-					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int32).Int32), 10), 1)
-				case reflect.TypeOf(null.Int64{}):
-					query = strings.Replace(query, "?", strconv.FormatInt(field.Interface().(null.Int64).Int64, 10), 1)
-				case reflect.TypeOf(null.Uint{}):
-					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint).Uint), 10), 1)
-				case reflect.TypeOf(null.Uint8{}):
-					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint8).Uint8), 10), 1)
-				case reflect.TypeOf(null.Uint16{}):
-					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint16).Uint16), 10), 1)
-				case reflect.TypeOf(null.Uint32{}):
-					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint32).Uint32), 10), 1)
-				case reflect.TypeOf(null.Uint64{}):
-					query = strings.Replace(query, "?", strconv.FormatUint(field.Interface().(null.Uint64).Uint64, 10), 1)
-				case reflect.TypeOf(null.String{}):
-					query = strings.Replace(query, "?", `"`+field.Interface().(null.String).String+`"`, 1)
-				case reflect.TypeOf(null.Bool{}):
-					if field.Interface().(null.Bool).Bool {
-						query = strings.Replace(query, "?", "1", 1)
-					} else {
-						query = strings.Replace(query, "?", "0", 1)
-					}
-				}
-			}
-		} else {
-			switch field.Kind() {
-			case reflect.Bool:
-				boolString := "0"
-				if field.Bool() {
-					boolString = "1"
-				}
-				query = strings.Replace(query, "?", boolString, 1)
-			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-				query = strings.Replace(query, "?", strconv.FormatInt(field.Int(), 10), 1)
-			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-				query = strings.Replace(query, "?", strconv.FormatUint(field.Uint(), 10), 1)
-			case reflect.String:
-				query = strings.Replace(query, "?", `"`+field.String()+`"`, 1)
-			default:
-				return "", errors.New("Dont know how to interpolate type " + field.Type().String())
-			}
-		}
-	}
-	return query, nil
-}
diff --git a/templates/07_relationship_to_one_eager.tpl b/templates/07_relationship_to_one_eager.tpl
index 28010fd..3b24f1a 100644
--- a/templates/07_relationship_to_one_eager.tpl
+++ b/templates/07_relationship_to_one_eager.tpl
@@ -40,11 +40,7 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 	)
 
 	if boil.DebugMode {
-    qStr, err := InterpolateParams(query, args...)
-    if err != nil {
-      return err
-    }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintf(boil.DebugWriter, "%s\n%v\n", query, args)
 	}
 
 	results, err := e.Query(query, args...)
diff --git a/templates/08_relationship_one_to_one_eager.tpl b/templates/08_relationship_one_to_one_eager.tpl
index 261b30c..37d1af0 100644
--- a/templates/08_relationship_one_to_one_eager.tpl
+++ b/templates/08_relationship_one_to_one_eager.tpl
@@ -40,11 +40,7 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 	)
 
 	if boil.DebugMode {
-    qStr, err := InterpolateParams(query, args...)
-    if err != nil {
-      return err
-    }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintf(boil.DebugWriter, "%s\n%v\n", query, args)
 	}
 
 	results, err := e.Query(query, args...)
diff --git a/templates/09_relationship_to_many_eager.tpl b/templates/09_relationship_to_many_eager.tpl
index 8c4159b..1603188 100644
--- a/templates/09_relationship_to_many_eager.tpl
+++ b/templates/09_relationship_to_many_eager.tpl
@@ -49,11 +49,7 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 		{{end -}}
 
 	if boil.DebugMode {
-    qStr, err := InterpolateParams(query, args...)
-    if err != nil {
-      return err
-    }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintf(boil.DebugWriter, "%s\n%v\n", query, args)
 	}
 
 	results, err := e.Query(query, args...)
diff --git a/templates/10_relationship_to_one_setops.tpl b/templates/10_relationship_to_one_setops.tpl
index 8362420..14f726e 100644
--- a/templates/10_relationship_to_one_setops.tpl
+++ b/templates/10_relationship_to_one_setops.tpl
@@ -53,11 +53,8 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 	values := []interface{}{related.{{$txt.ForeignTable.ColumnNameGo}}, o.{{$dot.Table.PKey.Columns | stringMap $dot.StringFuncs.titleCase | join ", o."}}{{"}"}}
 
 	if boil.DebugMode {
-    qStr, err := InterpolateParams(updateQuery, values...)
-    if err != nil {
-      return err
-    }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, updateQuery)
+		fmt.Fprintln(boil.DebugWriter, values)
 	}
 
 	if _, err = exec.Exec(updateQuery, values...); err != nil {
diff --git a/templates/11_relationship_one_to_one_setops.tpl b/templates/11_relationship_one_to_one_setops.tpl
index 7648e23..826eec2 100644
--- a/templates/11_relationship_one_to_one_setops.tpl
+++ b/templates/11_relationship_one_to_one_setops.tpl
@@ -59,11 +59,8 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 		values := []interface{}{o.{{$txt.LocalTable.ColumnNameGo}}, related.{{$foreignPKeyCols | stringMap $dot.StringFuncs.titleCase | join ", related."}}{{"}"}}
 
 		if boil.DebugMode {
-      qStr, err := InterpolateParams(updateQuery, values...)
-      if err != nil {
-        return err
-      }
-      fmt.Fprintln(boil.DebugWriter, qStr)
+			fmt.Fprintln(boil.DebugWriter, updateQuery)
+			fmt.Fprintln(boil.DebugWriter, values)
 		}
 
 		if _, err = exec.Exec(updateQuery, values...); err != nil {
diff --git a/templates/12_relationship_to_many_setops.tpl b/templates/12_relationship_to_many_setops.tpl
index 6794889..06159ee 100644
--- a/templates/12_relationship_to_many_setops.tpl
+++ b/templates/12_relationship_to_many_setops.tpl
@@ -66,11 +66,8 @@ func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}(exec boil.Executo
 			values := []interface{}{o.{{$txt.LocalTable.ColumnNameGo}}, rel.{{$foreignPKeyCols | stringMap $dot.StringFuncs.titleCase | join ", rel."}}{{"}"}}
 
 			if boil.DebugMode {
-        qStr, err := InterpolateParams(updateQuery, values...)
-        if err != nil {
-          return err
-        }
-        fmt.Fprintln(boil.DebugWriter, qStr)
+				fmt.Fprintln(boil.DebugWriter, updateQuery)
+				fmt.Fprintln(boil.DebugWriter, values)
 			}
 
 			if _, err = exec.Exec(updateQuery, values...); err != nil {
@@ -90,11 +87,8 @@ func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}(exec boil.Executo
 		values := []interface{}{{"{"}}o.{{$txt.LocalTable.ColumnNameGo}}, rel.{{$txt.ForeignTable.ColumnNameGo}}}
 
 		if boil.DebugMode {
-      qStr, err := InterpolateParams(query, values...)
-      if err != nil {
-        return err
-      }
-      fmt.Fprintln(boil.DebugWriter, qStr)
+			fmt.Fprintln(boil.DebugWriter, query)
+			fmt.Fprintln(boil.DebugWriter, values)
 		}
 
 		_, err = exec.Exec(query, values...)
@@ -190,11 +184,8 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 	values := []interface{}{{"{"}}o.{{$txt.LocalTable.ColumnNameGo}}}
 	{{end -}}
 	if boil.DebugMode {
-    qStr, err := InterpolateParams(query, values...)
-    if err != nil {
-      return err
-    }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, query)
+		fmt.Fprintln(boil.DebugWriter, values)
 	}
 
 	_, err := exec.Exec(query, values...)
@@ -269,11 +260,8 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}(exec boil.Exec
 	}
 
 	if boil.DebugMode {
-    qStr, err := InterpolateParams(query, values...)
-    if err != nil {
-      return err
-    }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, query)
+		fmt.Fprintln(boil.DebugWriter, values)
 	}
 
 	_, err = exec.Exec(query, values...)
diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index 00b6f5b..870e20d 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -98,11 +98,8 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 	vals := queries.ValuesFromMapping(value, cache.valueMapping)
 
 	if boil.DebugMode {
-	  qStr, err := InterpolateParams(cache.query, vals...)
-	  if err != nil {
-	    return err
-	  }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, cache.query)
+		fmt.Fprintln(boil.DebugWriter, vals)
 	}
 
 	{{if .UseLastInsertID -}}
@@ -147,11 +144,8 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 	}
 
 	if boil.DebugMode {
-	  qStr, err := InterpolateParams(cache.retQuery, identifierCols...)
-	  if err != nil {
-	    return err
-	  }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, cache.retQuery)
+		fmt.Fprintln(boil.DebugWriter, identifierCols...)
 	}
 
 	err = exec.QueryRow(cache.retQuery, identifierCols...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...)
diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index 1f67234..bc4a6f5 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -78,11 +78,8 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 	values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping)
 
 	if boil.DebugMode {
-	  qStr, err := InterpolateParams(cache.query, values...)
-	  if err != nil {
-	    return err
-	  }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, cache.query)
+		fmt.Fprintln(boil.DebugWriter, values)
 	}
 
 	_, err = exec.Exec(cache.query, values...)
@@ -173,11 +170,8 @@ func (o {{$tableNameSingular}}Slice) UpdateAll(exec boil.Executor, cols M) error
 		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), {{if .Dialect.IndexPlaceholders}}len(colNames)+1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns, len(o)))
 
 	if boil.DebugMode {
-	  qStr, err := InterpolateParams(sql, args...)
-	  if err != nil {
-	    return err
-	  }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, sql)
+		fmt.Fprintln(boil.DebugWriter, args...)
 	}
 
 	_, err := exec.Exec(sql, args...)
diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index 6eef9fe..dbce58c 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -147,11 +147,8 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 	}
 
 	if boil.DebugMode {
-	  qStr, err := InterpolateParams(cache.query, vals...)
-	  if err != nil {
-	    return err
-	  }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, cache.query)
+		fmt.Fprintln(boil.DebugWriter, vals)
 	}
 
 	{{if .UseLastInsertID -}}
@@ -196,11 +193,8 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 	}
 
 	if boil.DebugMode {
-	  qStr, err := InterpolateParams(cache.retQuery, identifierCols...)
-	  if err != nil {
-	    return err
-	  }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, cache.retQuery)
+		fmt.Fprintln(boil.DebugWriter, identifierCols...)
 	}
 
 	err = exec.QueryRow(cache.retQuery, identifierCols...).Scan(returns...)
diff --git a/templates/18_delete.tpl b/templates/18_delete.tpl
index 8c63e43..aea163e 100644
--- a/templates/18_delete.tpl
+++ b/templates/18_delete.tpl
@@ -6,7 +6,7 @@
 // Panics on error.
 func (o *{{$tableNameSingular}}) DeleteP(exec boil.Executor) {
 	if err := o.Delete(exec); err != nil {
-	  panic(boil.WrapErr(err))
+	panic(boil.WrapErr(err))
 	}
 }
 
@@ -46,11 +46,8 @@ func (o *{{$tableNameSingular}}) Delete(exec boil.Executor) error {
 	sql := "DELETE FROM {{$schemaTable}} WHERE {{if .Dialect.IndexPlaceholders}}{{whereClause .LQ .RQ 1 .Table.PKey.Columns}}{{else}}{{whereClause .LQ .RQ 0 .Table.PKey.Columns}}{{end}}"
 
 	if boil.DebugMode {
-	  qStr, err := InterpolateParams(sql, args...)
-	  if err != nil {
-	    return err
-	  }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+	fmt.Fprintln(boil.DebugWriter, sql)
+	fmt.Fprintln(boil.DebugWriter, args...)
 	}
 
 	_, err := exec.Exec(sql, args...)
@@ -142,11 +139,8 @@ func (o {{$tableNameSingular}}Slice) DeleteAll(exec boil.Executor) error {
 		strmangle.WhereClauseRepeated(string(dialect.LQ), string(dialect.RQ), {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns, len(o))
 
 	if boil.DebugMode {
-	  qStr, err := InterpolateParams(sql, args...)
-	  if err != nil {
-	    return err
-	  }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, sql)
+		fmt.Fprintln(boil.DebugWriter, args)
 	}
 
 	_, err := exec.Exec(sql, args...)
diff --git a/templates/20_exists.tpl b/templates/20_exists.tpl
index 7d3dc3d..2e20fa6 100644
--- a/templates/20_exists.tpl
+++ b/templates/20_exists.tpl
@@ -14,11 +14,8 @@ func {{$tableNameSingular}}Exists(exec boil.Executor, {{$pkArgs}}) (bool, error)
 	{{- end}}
 
 	if boil.DebugMode {
-	  qStr, err := InterpolateParams(sql, {{$pkNames | join ", "}})
-	  if err != nil {
-	    return false, err
-	  }
-    fmt.Fprintln(boil.DebugWriter, qStr)
+		fmt.Fprintln(boil.DebugWriter, sql)
+		fmt.Fprintln(boil.DebugWriter, {{$pkNames | join ", "}})
 	}
 
 	row := exec.QueryRow(sql, {{$pkNames | join ", "}})
diff --git a/templates/singleton/boil_queries.tpl b/templates/singleton/boil_queries.tpl
index 89b0e74..1260dde 100644
--- a/templates/singleton/boil_queries.tpl
+++ b/templates/singleton/boil_queries.tpl
@@ -136,69 +136,3 @@ func checkMerge(tx boil.Executor, foreignKeys []foreignKey) error {
 
 	return nil
 }
-
-// duplicated in queries/query.go
-func InterpolateParams(query string, args ...interface{}) (string, error) {
-	for i := 0; i < len(args); i++ {
-		field := reflect.ValueOf(args[i])
-
-		if value, ok := field.Interface().(time.Time); ok {
-			query = strings.Replace(query, "?", `"`+value.Format("2006-01-02 15:04:05")+`"`, 1)
-		} else if nullable, ok := field.Interface().(null.Nullable); ok {
-			if nullable.IsNull() {
-				query = strings.Replace(query, "?", "NULL", 1)
-			} else {
-				switch field.Type() {
-				case reflect.TypeOf(null.Time{}):
-					query = strings.Replace(query, "?", `"`+field.Interface().(null.Time).Time.Format("2006-01-02 15:04:05")+`"`, 1)
-				case reflect.TypeOf(null.Int{}):
-					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int).Int), 10), 1)
-				case reflect.TypeOf(null.Int8{}):
-					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int8).Int8), 10), 1)
-				case reflect.TypeOf(null.Int16{}):
-					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int16).Int16), 10), 1)
-				case reflect.TypeOf(null.Int32{}):
-					query = strings.Replace(query, "?", strconv.FormatInt(int64(field.Interface().(null.Int32).Int32), 10), 1)
-				case reflect.TypeOf(null.Int64{}):
-					query = strings.Replace(query, "?", strconv.FormatInt(field.Interface().(null.Int64).Int64, 10), 1)
-				case reflect.TypeOf(null.Uint{}):
-					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint).Uint), 10), 1)
-				case reflect.TypeOf(null.Uint8{}):
-					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint8).Uint8), 10), 1)
-				case reflect.TypeOf(null.Uint16{}):
-					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint16).Uint16), 10), 1)
-				case reflect.TypeOf(null.Uint32{}):
-					query = strings.Replace(query, "?", strconv.FormatUint(uint64(field.Interface().(null.Uint32).Uint32), 10), 1)
-				case reflect.TypeOf(null.Uint64{}):
-					query = strings.Replace(query, "?", strconv.FormatUint(field.Interface().(null.Uint64).Uint64, 10), 1)
-				case reflect.TypeOf(null.String{}):
-					query = strings.Replace(query, "?", `"`+field.Interface().(null.String).String+`"`, 1)
-				case reflect.TypeOf(null.Bool{}):
-					if field.Interface().(null.Bool).Bool {
-						query = strings.Replace(query, "?", "1", 1)
-					} else {
-						query = strings.Replace(query, "?", "0", 1)
-					}
-				}
-			}
-		} else {
-			switch field.Kind() {
-			case reflect.Bool:
-				boolString := "0"
-				if field.Bool() {
-					boolString = "1"
-				}
-				query = strings.Replace(query, "?", boolString, 1)
-			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-				query = strings.Replace(query, "?", strconv.FormatInt(field.Int(), 10), 1)
-			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-				query = strings.Replace(query, "?", strconv.FormatUint(field.Uint(), 10), 1)
-			case reflect.String:
-				query = strings.Replace(query, "?", `"`+field.String()+`"`, 1)
-			default:
-				return "", errors.New("Dont know how to interpolate type " + field.Type().String())
-			}
-		}
-	}
-	return query, nil
-}

From 0b0a1f21c2c3512b0f08441302e5b2e1fce7fc9a Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Sat, 2 Sep 2017 11:52:31 -0400
Subject: [PATCH 166/179] allow generic interface or real sql tx

---
 boil/db.go | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/boil/db.go b/boil/db.go
index 2d31d38..f3153bc 100644
--- a/boil/db.go
+++ b/boil/db.go
@@ -22,11 +22,19 @@ type Beginner interface {
 	Begin() (Transactor, error)
 }
 
+type SQLBeginner interface {
+	Begin() (*sql.Tx, error)
+}
+
 // Begin a transaction
 func Begin() (Transactor, error) {
 	creator, ok := currentDB.(Beginner)
 	if !ok {
-		panic("database does not support transactions")
+		creator2, ok2 := currentDB.(SQLBeginner)
+		if !ok2 {
+			panic("database does not support transactions")
+		}
+		return creator2.Begin()
 	}
 
 	return creator.Begin()

From e4a52e21b6f0c655dc21b5ba4391bbdf1f3d1abd Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Wed, 7 Feb 2018 09:35:46 -0500
Subject: [PATCH 167/179] switch to our errors package

---
 boil/errors.go                                | 23 -------------
 boil/errors_test.go                           | 24 -------------
 boilingcore/imports.go                        | 26 +++++++-------
 queries/query.go                              |  5 +--
 queries/reflect.go                            |  6 ++--
 templates/02_hooks.tpl                        | 18 +++++-----
 templates/03_finishers.tpl                    | 18 +++++-----
 templates/07_relationship_to_one_eager.tpl    |  6 ++--
 .../08_relationship_one_to_one_eager.tpl      |  6 ++--
 templates/09_relationship_to_many_eager.tpl   | 10 +++---
 templates/10_relationship_to_one_setops.tpl   | 14 ++++----
 .../11_relationship_one_to_one_setops.tpl     | 14 ++++----
 templates/12_relationship_to_many_setops.tpl  | 24 ++++++-------
 templates/14_find.tpl                         | 12 +++----
 templates/15_insert.tpl                       | 20 +++++------
 templates/16_update.tpl                       | 24 ++++++-------
 templates/17_upsert.tpl                       | 24 ++++++-------
 templates/18_delete.tpl                       | 34 +++++++++----------
 templates/19_reload.tpl                       | 16 ++++-----
 templates/20_exists.tpl                       |  6 ++--
 templates/23_merge.tpl                        | 16 ++++-----
 templates/singleton/boil_queries.tpl          | 18 +++++-----
 templates/singleton/boil_types.tpl            |  2 +-
 templates_test/main_test/mssql_main.tpl       | 14 ++++----
 templates_test/main_test/mysql_main.tpl       | 22 ++++++------
 templates_test/main_test/postgres_main.tpl    | 22 ++++++------
 templates_test/singleton/boil_main_test.tpl   |  2 +-
 27 files changed, 190 insertions(+), 236 deletions(-)
 delete mode 100644 boil/errors.go
 delete mode 100644 boil/errors_test.go

diff --git a/boil/errors.go b/boil/errors.go
deleted file mode 100644
index 4d02169..0000000
--- a/boil/errors.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package boil
-
-type boilErr struct {
-	error
-}
-
-// WrapErr wraps err in a boilErr
-func WrapErr(err error) error {
-	return boilErr{
-		error: err,
-	}
-}
-
-// Error returns the underlying error string
-func (e boilErr) Error() string {
-	return e.error.Error()
-}
-
-// IsBoilErr checks if err is a boilErr
-func IsBoilErr(err error) bool {
-	_, ok := err.(boilErr)
-	return ok
-}
diff --git a/boil/errors_test.go b/boil/errors_test.go
deleted file mode 100644
index 2b2f1a0..0000000
--- a/boil/errors_test.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package boil
-
-import (
-	"errors"
-	"testing"
-)
-
-func TestErrors(t *testing.T) {
-	t.Parallel()
-
-	err := errors.New("test error")
-	if IsBoilErr(err) == true {
-		t.Errorf("Expected false")
-	}
-
-	err = WrapErr(errors.New("test error"))
-	if err.Error() != "test error" {
-		t.Errorf(`Expected "test error", got %v`, err.Error())
-	}
-
-	if IsBoilErr(err) != true {
-		t.Errorf("Expected true")
-	}
-}
diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index 13ed119..b73b429 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -170,12 +170,12 @@ func newImporter() importer {
 			`"time"`,
 		},
 		thirdParty: importList{
+			`"github.com/lbryio/errors.go"`,
 			`"github.com/lbryio/null.go"`,
 			`"github.com/lbryio/sqlboiler/boil"`,
 			`"github.com/lbryio/sqlboiler/queries"`,
 			`"github.com/lbryio/sqlboiler/queries/qm"`,
 			`"github.com/lbryio/sqlboiler/strmangle"`,
-			`"github.com/pkg/errors"`,
 		},
 	}
 
@@ -185,16 +185,16 @@ func newImporter() importer {
 				`"fmt"`,
 			},
 			thirdParty: importList{
+				`"github.com/lbryio/errors.go"`,
 				`"github.com/lbryio/sqlboiler/boil"`,
 				`"github.com/lbryio/sqlboiler/queries"`,
 				`"github.com/lbryio/sqlboiler/queries/qm"`,
 				`"github.com/lbryio/sqlboiler/strmangle"`,
-				`"github.com/pkg/errors"`,
 			},
 		},
 		"boil_types": {
 			thirdParty: importList{
-				`"github.com/pkg/errors"`,
+				`"github.com/lbryio/errors.go"`,
 				`"github.com/lbryio/sqlboiler/strmangle"`,
 			},
 		},
@@ -227,9 +227,9 @@ func newImporter() importer {
 			},
 			thirdParty: importList{
 				`"github.com/kat-co/vala"`,
-				`"github.com/pkg/errors"`,
-				`"github.com/spf13/viper"`,
+				`"github.com/lbryio/errors.go"`,
 				`"github.com/lbryio/sqlboiler/boil"`,
+				`"github.com/spf13/viper"`,
 			},
 		},
 		"boil_queries_test": {
@@ -265,11 +265,11 @@ func newImporter() importer {
 				`"strings"`,
 			},
 			thirdParty: importList{
-				`"github.com/pkg/errors"`,
-				`"github.com/spf13/viper"`,
+				`"github.com/lbryio/errors.go"`,
 				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
 				`"github.com/lbryio/sqlboiler/randomize"`,
 				`_ "github.com/lib/pq"`,
+				`"github.com/spf13/viper"`,
 			},
 		},
 		"mysql": {
@@ -284,11 +284,11 @@ func newImporter() importer {
 				`"strings"`,
 			},
 			thirdParty: importList{
-				`"github.com/pkg/errors"`,
-				`"github.com/spf13/viper"`,
+				`_ "github.com/go-sql-driver/mysql"`,
+				`"github.com/lbryio/errors.go"`,
 				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
 				`"github.com/lbryio/sqlboiler/randomize"`,
-				`_ "github.com/go-sql-driver/mysql"`,
+				`"github.com/spf13/viper"`,
 			},
 		},
 		"mssql": {
@@ -301,11 +301,11 @@ func newImporter() importer {
 				`"strings"`,
 			},
 			thirdParty: importList{
-				`"github.com/pkg/errors"`,
-				`"github.com/spf13/viper"`,
+				`_ "github.com/denisenkom/go-mssqldb"`,
+				`"github.com/lbryio/errors.go"`,
 				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
 				`"github.com/lbryio/sqlboiler/randomize"`,
-				`_ "github.com/denisenkom/go-mssqldb"`,
+				`"github.com/spf13/viper"`,
 			},
 		},
 	}
diff --git a/queries/query.go b/queries/query.go
index be539e5..a76c046 100644
--- a/queries/query.go
+++ b/queries/query.go
@@ -4,6 +4,7 @@ import (
 	"database/sql"
 	"fmt"
 
+	"github.com/lbryio/errors.go"
 	"github.com/lbryio/sqlboiler/boil"
 )
 
@@ -136,7 +137,7 @@ func (q *Query) Query() (*sql.Rows, error) {
 func (q *Query) ExecP() sql.Result {
 	res, err := q.Exec()
 	if err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 
 	return res
@@ -147,7 +148,7 @@ func (q *Query) ExecP() sql.Result {
 func (q *Query) QueryP() *sql.Rows {
 	rows, err := q.Query()
 	if err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 
 	return rows
diff --git a/queries/reflect.go b/queries/reflect.go
index 8cf8f3d..39eda23 100644
--- a/queries/reflect.go
+++ b/queries/reflect.go
@@ -7,9 +7,9 @@ import (
 	"strings"
 	"sync"
 
-	"github.com/pkg/errors"
-	"github.com/lbryio/sqlboiler/boil"
 	"github.com/lbryio/sqlboiler/strmangle"
+
+	"github.com/pkg/errors"
 )
 
 var (
@@ -41,7 +41,7 @@ const (
 // It panics on error. See boil.Bind() documentation.
 func (q *Query) BindP(obj interface{}) {
 	if err := q.Bind(obj); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.WithStack(err))
 	}
 }
 
diff --git a/templates/02_hooks.tpl b/templates/02_hooks.tpl
index 9815639..d152978 100644
--- a/templates/02_hooks.tpl
+++ b/templates/02_hooks.tpl
@@ -16,7 +16,7 @@ var {{$varNameSingular}}AfterUpsertHooks []{{$tableNameSingular}}Hook
 func (o *{{$tableNameSingular}}) doBeforeInsertHooks(exec boil.Executor) (err error) {
 	for _, hook := range {{$varNameSingular}}BeforeInsertHooks {
 		if err := hook(exec, o); err != nil {
-			return err
+			return errors.Err(err)
 		}
 	}
 
@@ -27,7 +27,7 @@ func (o *{{$tableNameSingular}}) doBeforeInsertHooks(exec boil.Executor) (err er
 func (o *{{$tableNameSingular}}) doBeforeUpdateHooks(exec boil.Executor) (err error) {
 	for _, hook := range {{$varNameSingular}}BeforeUpdateHooks {
 		if err := hook(exec, o); err != nil {
-			return err
+			return errors.Err(err)
 		}
 	}
 
@@ -38,7 +38,7 @@ func (o *{{$tableNameSingular}}) doBeforeUpdateHooks(exec boil.Executor) (err er
 func (o *{{$tableNameSingular}}) doBeforeDeleteHooks(exec boil.Executor) (err error) {
 	for _, hook := range {{$varNameSingular}}BeforeDeleteHooks {
 		if err := hook(exec, o); err != nil {
-			return err
+			return errors.Err(err)
 		}
 	}
 
@@ -49,7 +49,7 @@ func (o *{{$tableNameSingular}}) doBeforeDeleteHooks(exec boil.Executor) (err er
 func (o *{{$tableNameSingular}}) doBeforeUpsertHooks(exec boil.Executor) (err error) {
 	for _, hook := range {{$varNameSingular}}BeforeUpsertHooks {
 		if err := hook(exec, o); err != nil {
-			return err
+			return errors.Err(err)
 		}
 	}
 
@@ -60,7 +60,7 @@ func (o *{{$tableNameSingular}}) doBeforeUpsertHooks(exec boil.Executor) (err er
 func (o *{{$tableNameSingular}}) doAfterInsertHooks(exec boil.Executor) (err error) {
 	for _, hook := range {{$varNameSingular}}AfterInsertHooks {
 		if err := hook(exec, o); err != nil {
-			return err
+			return errors.Err(err)
 		}
 	}
 
@@ -71,7 +71,7 @@ func (o *{{$tableNameSingular}}) doAfterInsertHooks(exec boil.Executor) (err err
 func (o *{{$tableNameSingular}}) doAfterSelectHooks(exec boil.Executor) (err error) {
 	for _, hook := range {{$varNameSingular}}AfterSelectHooks {
 		if err := hook(exec, o); err != nil {
-			return err
+			return errors.Err(err)
 		}
 	}
 
@@ -82,7 +82,7 @@ func (o *{{$tableNameSingular}}) doAfterSelectHooks(exec boil.Executor) (err err
 func (o *{{$tableNameSingular}}) doAfterUpdateHooks(exec boil.Executor) (err error) {
 	for _, hook := range {{$varNameSingular}}AfterUpdateHooks {
 		if err := hook(exec, o); err != nil {
-			return err
+			return errors.Err(err)
 		}
 	}
 
@@ -93,7 +93,7 @@ func (o *{{$tableNameSingular}}) doAfterUpdateHooks(exec boil.Executor) (err err
 func (o *{{$tableNameSingular}}) doAfterDeleteHooks(exec boil.Executor) (err error) {
 	for _, hook := range {{$varNameSingular}}AfterDeleteHooks {
 		if err := hook(exec, o); err != nil {
-			return err
+			return errors.Err(err)
 		}
 	}
 
@@ -104,7 +104,7 @@ func (o *{{$tableNameSingular}}) doAfterDeleteHooks(exec boil.Executor) (err err
 func (o *{{$tableNameSingular}}) doAfterUpsertHooks(exec boil.Executor) (err error) {
 	for _, hook := range {{$varNameSingular}}AfterUpsertHooks {
 		if err := hook(exec, o); err != nil {
-			return err
+			return errors.Err(err)
 		}
 	}
 
diff --git a/templates/03_finishers.tpl b/templates/03_finishers.tpl
index df2081d..473bddd 100644
--- a/templates/03_finishers.tpl
+++ b/templates/03_finishers.tpl
@@ -4,7 +4,7 @@
 func (q {{$tableNameSingular}}Query) OneP() (*{{$tableNameSingular}}) {
 	o, err := q.One()
 	if err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 
 	return o
@@ -18,10 +18,10 @@ func (q {{$tableNameSingular}}Query) One() (*{{$tableNameSingular}}, error) {
 
 	err := q.Bind(o)
 	if err != nil {
-		if errors.Cause(err) == sql.ErrNoRows {
+		if errors.Is(err, sql.ErrNoRows) {
 			return nil, nil
 		}
-		return nil, errors.Wrap(err, "{{.PkgName}}: failed to execute a one query for {{.Table.Name}}")
+		return nil, errors.Prefix("{{.PkgName}}: failed to execute a one query for {{.Table.Name}}", err)
 	}
 
 	{{if not .NoHooks -}}
@@ -37,7 +37,7 @@ func (q {{$tableNameSingular}}Query) One() (*{{$tableNameSingular}}, error) {
 func (q {{$tableNameSingular}}Query) AllP() {{$tableNameSingular}}Slice {
 	o, err := q.All()
 	if err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 
 	return o
@@ -49,7 +49,7 @@ func (q {{$tableNameSingular}}Query) All() ({{$tableNameSingular}}Slice, error)
 
 	err := q.Bind(&o)
 	if err != nil {
-		return nil, errors.Wrap(err, "{{.PkgName}}: failed to assign all query results to {{$tableNameSingular}} slice")
+		return nil, errors.Prefix("{{.PkgName}}: failed to assign all query results to {{$tableNameSingular}} slice", err)
 	}
 
 	{{if not .NoHooks -}}
@@ -69,7 +69,7 @@ func (q {{$tableNameSingular}}Query) All() ({{$tableNameSingular}}Slice, error)
 func (q {{$tableNameSingular}}Query) CountP() int64 {
 	c, err := q.Count()
 	if err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 
 	return c
@@ -84,7 +84,7 @@ func (q {{$tableNameSingular}}Query) Count() (int64, error) {
 
 	err := q.Query.QueryRow().Scan(&count)
 	if err != nil {
-		return 0, errors.Wrap(err, "{{.PkgName}}: failed to count {{.Table.Name}} rows")
+		return 0, errors.Prefix("{{.PkgName}}: failed to count {{.Table.Name}} rows", err)
 	}
 
 	return count, nil
@@ -94,7 +94,7 @@ func (q {{$tableNameSingular}}Query) Count() (int64, error) {
 func (q {{$tableNameSingular}}Query) ExistsP() bool {
 	e, err := q.Exists()
 	if err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 
 	return e
@@ -110,7 +110,7 @@ func (q {{$tableNameSingular}}Query) Exists() (bool, error) {
 
 	err := q.Query.QueryRow().Scan(&count)
 	if err != nil {
-		return false, errors.Wrap(err, "{{.PkgName}}: failed to check if {{.Table.Name}} exists")
+		return false, errors.Prefix("{{.PkgName}}: failed to check if {{.Table.Name}} exists", err)
 	}
 
 	return count > 0, nil
diff --git a/templates/07_relationship_to_one_eager.tpl b/templates/07_relationship_to_one_eager.tpl
index 3b24f1a..f6bba5b 100644
--- a/templates/07_relationship_to_one_eager.tpl
+++ b/templates/07_relationship_to_one_eager.tpl
@@ -45,20 +45,20 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 
 	results, err := e.Query(query, args...)
 	if err != nil {
-		return errors.Wrap(err, "failed to eager load {{$txt.ForeignTable.NameGo}}")
+		return errors.Prefix("failed to eager load {{$txt.ForeignTable.NameGo}}", err)
 	}
 	defer results.Close()
 
 	var resultSlice []*{{$txt.ForeignTable.NameGo}}
 	if err = queries.Bind(results, &resultSlice); err != nil {
-		return errors.Wrap(err, "failed to bind eager loaded slice {{$txt.ForeignTable.NameGo}}")
+		return errors.Prefix("failed to bind eager loaded slice {{$txt.ForeignTable.NameGo}}", err)
 	}
 
 	{{if not $dot.NoHooks -}}
 	if len({{$varNameSingular}}AfterSelectHooks) != 0 {
 		for _, obj := range resultSlice {
 			if err := obj.doAfterSelectHooks(e); err != nil {
-				return err
+				return errors.Err(err)
 			}
 		}
 	}
diff --git a/templates/08_relationship_one_to_one_eager.tpl b/templates/08_relationship_one_to_one_eager.tpl
index 37d1af0..cd587fc 100644
--- a/templates/08_relationship_one_to_one_eager.tpl
+++ b/templates/08_relationship_one_to_one_eager.tpl
@@ -45,20 +45,20 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 
 	results, err := e.Query(query, args...)
 	if err != nil {
-		return errors.Wrap(err, "failed to eager load {{$txt.ForeignTable.NameGo}}")
+		return errors.Prefix("failed to eager load {{$txt.ForeignTable.NameGo}}", err)
 	}
 	defer results.Close()
 
 	var resultSlice []*{{$txt.ForeignTable.NameGo}}
 	if err = queries.Bind(results, &resultSlice); err != nil {
-		return errors.Wrap(err, "failed to bind eager loaded slice {{$txt.ForeignTable.NameGo}}")
+		return errors.Prefix("failed to bind eager loaded slice {{$txt.ForeignTable.NameGo}}", err)
 	}
 
 	{{if not $dot.NoHooks -}}
 	if len({{$varNameSingular}}AfterSelectHooks) != 0 {
 		for _, obj := range resultSlice {
 			if err := obj.doAfterSelectHooks(e); err != nil {
-				return err
+				return errors.Err(err)
 			}
 		}
 	}
diff --git a/templates/09_relationship_to_many_eager.tpl b/templates/09_relationship_to_many_eager.tpl
index 1603188..f3fd2c4 100644
--- a/templates/09_relationship_to_many_eager.tpl
+++ b/templates/09_relationship_to_many_eager.tpl
@@ -54,7 +54,7 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 
 	results, err := e.Query(query, args...)
 	if err != nil {
-		return errors.Wrap(err, "failed to eager load {{.ForeignTable}}")
+		return errors.Prefix("failed to eager load {{.ForeignTable}}", err)
 	}
 	defer results.Close()
 
@@ -70,7 +70,7 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 
 		err = results.Scan({{$foreignTable.Columns | columnNames | stringMap $dot.StringFuncs.titleCase | prefixStringSlice "&one." | join ", "}}, &localJoinCol)
 		if err = results.Err(); err != nil {
-			return errors.Wrap(err, "failed to plebian-bind eager loaded slice {{.ForeignTable}}")
+			return errors.Prefix("failed to plebian-bind eager loaded slice {{.ForeignTable}}", err)
 		}
 
 		resultSlice = append(resultSlice, one)
@@ -78,11 +78,11 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 	}
 
 	if err = results.Err(); err != nil {
-		return errors.Wrap(err, "failed to plebian-bind eager loaded slice {{.ForeignTable}}")
+		return errors.Prefix("failed to plebian-bind eager loaded slice {{.ForeignTable}}", err)
 	}
 	{{else -}}
 	if err = queries.Bind(results, &resultSlice); err != nil {
-		return errors.Wrap(err, "failed to bind eager loaded slice {{.ForeignTable}}")
+		return errors.Prefix("failed to bind eager loaded slice {{.ForeignTable}}", err)
 	}
 	{{end}}
 
@@ -90,7 +90,7 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
 	if len({{.ForeignTable | singular | camelCase}}AfterSelectHooks) != 0 {
 		for _, obj := range resultSlice {
 			if err := obj.doAfterSelectHooks(e); err != nil {
-				return err
+				return errors.Err(err)
 			}
 		}
 	}
diff --git a/templates/10_relationship_to_one_setops.tpl b/templates/10_relationship_to_one_setops.tpl
index 14f726e..200adc3 100644
--- a/templates/10_relationship_to_one_setops.tpl
+++ b/templates/10_relationship_to_one_setops.tpl
@@ -20,7 +20,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}G(insert bool, rel
 // Panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}P(exec boil.Executor, insert bool, related *{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Set{{$txt.Function.Name}}(exec, insert, related); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -30,7 +30,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}P(exec boil.Execut
 // Uses the global database handle and panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}GP(insert bool, related *{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Set{{$txt.Function.Name}}(boil.GetDB(), insert, related); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -41,7 +41,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 	var err error
 	if insert {
 		if err = related.Insert(exec); err != nil {
-			return errors.Wrap(err, "failed to insert into foreign table")
+			return errors.Prefix("failed to insert into foreign table", err)
 		}
 	}
 
@@ -58,7 +58,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 	}
 
 	if _, err = exec.Exec(updateQuery, values...); err != nil {
-		return errors.Wrap(err, "failed to update local table")
+		return errors.Prefix("failed to update local table", err)
 	}
 
 	o.{{$txt.Function.LocalAssignment}} = related.{{$txt.Function.ForeignAssignment}}
@@ -110,7 +110,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}G(related *{{$t
 // Panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}P(exec boil.Executor, related *{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Remove{{$txt.Function.Name}}(exec, related); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -120,7 +120,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}P(exec boil.Exe
 // Uses the global database handle and panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}GP(related *{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Remove{{$txt.Function.Name}}(boil.GetDB(), related); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -133,7 +133,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}(exec boil.Exec
 	o.{{$txt.LocalTable.ColumnNameGo}}.Valid = false
 	if err = o.Update(exec, "{{.Column}}"); err != nil {
 		o.{{$txt.LocalTable.ColumnNameGo}}.Valid = true
-		return errors.Wrap(err, "failed to update local table")
+		return errors.Prefix("failed to update local table", err)
 	}
 
 	o.R.{{$txt.Function.Name}} = nil
diff --git a/templates/11_relationship_one_to_one_setops.tpl b/templates/11_relationship_one_to_one_setops.tpl
index 826eec2..29ce0a1 100644
--- a/templates/11_relationship_one_to_one_setops.tpl
+++ b/templates/11_relationship_one_to_one_setops.tpl
@@ -21,7 +21,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}G(insert bool, rel
 // Panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}P(exec boil.Executor, insert bool, related *{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Set{{$txt.Function.Name}}(exec, insert, related); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -31,7 +31,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}P(exec boil.Execut
 // Uses the global database handle and panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}GP(insert bool, related *{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Set{{$txt.Function.Name}}(boil.GetDB(), insert, related); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -48,7 +48,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 		{{- end}}
 
 		if err = related.Insert(exec); err != nil {
-			return errors.Wrap(err, "failed to insert into foreign table")
+			return errors.Prefix("failed to insert into foreign table", err)
 		}
 	} else {
 		updateQuery := fmt.Sprintf(
@@ -64,7 +64,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 		}
 
 		if _, err = exec.Exec(updateQuery, values...); err != nil {
-			return errors.Wrap(err, "failed to update foreign table")
+			return errors.Prefix("failed to update foreign table", err)
 		}
 
 		related.{{$txt.Function.ForeignAssignment}} = o.{{$txt.Function.LocalAssignment}}
@@ -107,7 +107,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}G(related *{{$t
 // Panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}P(exec boil.Executor, related *{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Remove{{$txt.Function.Name}}(exec, related); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -117,7 +117,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}P(exec boil.Exe
 // Uses the global database handle and panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}GP(related *{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Remove{{$txt.Function.Name}}(boil.GetDB(), related); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -130,7 +130,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}(exec boil.Exec
 	related.{{$txt.ForeignTable.ColumnNameGo}}.Valid = false
 	if err = related.Update(exec, "{{.ForeignColumn}}"); err != nil {
 		related.{{$txt.ForeignTable.ColumnNameGo}}.Valid = true
-		return errors.Wrap(err, "failed to update local table")
+		return errors.Prefix("failed to update local table", err)
 	}
 
 	o.R.{{$txt.Function.Name}} = nil
diff --git a/templates/12_relationship_to_many_setops.tpl b/templates/12_relationship_to_many_setops.tpl
index 06159ee..e54c2fd 100644
--- a/templates/12_relationship_to_many_setops.tpl
+++ b/templates/12_relationship_to_many_setops.tpl
@@ -24,7 +24,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}G(insert bool, rel
 // Panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}P(exec boil.Executor, insert bool, related ...*{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Add{{$txt.Function.Name}}(exec, insert, related...); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -35,7 +35,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}P(exec boil.Execut
 // Uses the global database handle and panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}GP(insert bool, related ...*{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Add{{$txt.Function.Name}}(boil.GetDB(), insert, related...); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -55,7 +55,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}(exec boil.Executo
 			{{end -}}
 
 			if err = rel.Insert(exec); err != nil {
-				return errors.Wrap(err, "failed to insert into foreign table")
+				return errors.Prefix("failed to insert into foreign table", err)
 			}
 		}{{if not .ToJoinTable}} else {
 			updateQuery := fmt.Sprintf(
@@ -71,7 +71,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}(exec boil.Executo
 			}
 
 			if _, err = exec.Exec(updateQuery, values...); err != nil {
-				return errors.Wrap(err, "failed to update foreign table")
+				return errors.Prefix("failed to update foreign table", err)
 			}
 
 			rel.{{$txt.Function.ForeignAssignment}} = o.{{$txt.Function.LocalAssignment}}
@@ -93,7 +93,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}(exec boil.Executo
 
 		_, err = exec.Exec(query, values...)
 		if err != nil {
-			return errors.Wrap(err, "failed to insert into join table")
+			return errors.Prefix("failed to insert into join table", err)
 		}
 	}
 	{{end -}}
@@ -152,7 +152,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}G(insert bool, rel
 // Panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}P(exec boil.Executor, insert bool, related ...*{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Set{{$txt.Function.Name}}(exec, insert, related...); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -165,7 +165,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}P(exec boil.Execut
 // Uses the global database handle and panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}GP(insert bool, related ...*{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Set{{$txt.Function.Name}}(boil.GetDB(), insert, related...); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -190,7 +190,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
 
 	_, err := exec.Exec(query, values...)
 	if err != nil {
-		return errors.Wrap(err, "failed to remove relationships before set")
+		return errors.Prefix("failed to remove relationships before set", err)
 	}
 
 	{{if .ToJoinTable -}}
@@ -230,7 +230,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}G(related ...*{
 // Panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}P(exec boil.Executor, related ...*{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Remove{{$txt.Function.Name}}(exec, related...); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -240,7 +240,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}P(exec boil.Exe
 // Uses the global database handle and panics on error.
 func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}GP(related ...*{{$txt.ForeignTable.NameGo}}) {
 	if err := o.Remove{{$txt.Function.Name}}(boil.GetDB(), related...); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -266,7 +266,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}(exec boil.Exec
 
 	_, err = exec.Exec(query, values...)
 	if err != nil {
-		return errors.Wrap(err, "failed to remove relationships before set")
+		return errors.Prefix("failed to remove relationships before set", err)
 	}
 	{{else -}}
 	for _, rel := range related {
@@ -277,7 +277,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}(exec boil.Exec
 		}
 		{{end -}}
 		if err = rel.Update(exec, "{{.ForeignColumn}}"); err != nil {
-			return err
+			return errors.Err(err)
 		}
 	}
 	{{end -}}
diff --git a/templates/14_find.tpl b/templates/14_find.tpl
index b7f69db..f9a88c8 100644
--- a/templates/14_find.tpl
+++ b/templates/14_find.tpl
@@ -12,7 +12,7 @@ func Find{{$tableNameSingular}}G({{$pkArgs}}, selectCols ...string) (*{{$tableNa
 func Find{{$tableNameSingular}}GP({{$pkArgs}}, selectCols ...string) *{{$tableNameSingular}} {
 	retobj, err := Find{{$tableNameSingular}}(boil.GetDB(), {{$pkNames | join ", "}}, selectCols...)
 	if err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 
 	return retobj
@@ -35,10 +35,10 @@ func Find{{$tableNameSingular}}(exec boil.Executor, {{$pkArgs}}, selectCols ...s
 
 	err := q.Bind({{$varNameSingular}}Obj)
 	if err != nil {
-		if errors.Cause(err) == sql.ErrNoRows {
+		if errors.Is(err, sql.ErrNoRows) {
 			return nil, nil
 		}
-		return nil, errors.Wrap(err, "{{.PkgName}}: unable to select from {{.Table.Name}}")
+		return nil, errors.Prefix("{{.PkgName}}: unable to select from {{.Table.Name}}", err)
 	}
 
 	return {{$varNameSingular}}Obj, nil
@@ -48,7 +48,7 @@ func Find{{$tableNameSingular}}(exec boil.Executor, {{$pkArgs}}, selectCols ...s
 func Find{{$tableNameSingular}}P(exec boil.Executor, {{$pkArgs}}, selectCols ...string) *{{$tableNameSingular}} {
 	retobj, err := Find{{$tableNameSingular}}(exec, {{$pkNames | join ", "}}, selectCols...)
 	if err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 
 	return retobj
@@ -64,10 +64,10 @@ func FindOne{{$tableNameSingular}}(exec boil.Executor, filters {{$tableNameSingu
     Bind(obj)
 
 	if err != nil {
-		if errors.Cause(err) == sql.ErrNoRows {
+		if errors.Is(err, sql.ErrNoRows) {
 			return nil, nil
 		}
-		return nil, errors.Wrap(err, "{{.PkgName}}: unable to select from {{.Table.Name}}")
+		return nil, errors.Prefix("{{.PkgName}}: unable to select from {{.Table.Name}}", err)
 	}
 
 	return obj, nil
diff --git a/templates/15_insert.tpl b/templates/15_insert.tpl
index 870e20d..20905ac 100644
--- a/templates/15_insert.tpl
+++ b/templates/15_insert.tpl
@@ -10,7 +10,7 @@ func (o *{{$tableNameSingular}}) InsertG(whitelist ... string) error {
 // behavior description.
 func (o *{{$tableNameSingular}}) InsertGP(whitelist ... string) {
 	if err := o.Insert(boil.GetDB(), whitelist...); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -18,7 +18,7 @@ func (o *{{$tableNameSingular}}) InsertGP(whitelist ... string) {
 // for whitelist behavior description.
 func (o *{{$tableNameSingular}}) InsertP(exec boil.Executor, whitelist ... string) {
 	if err := o.Insert(exec, whitelist...); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -29,7 +29,7 @@ func (o *{{$tableNameSingular}}) InsertP(exec boil.Executor, whitelist ... strin
 // - All columns with a default, but non-zero are included (i.e. health = 75)
 func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string) error {
 	if o == nil {
-		return errors.New("{{.PkgName}}: no {{.Table.Name}} provided for insertion")
+		return errors.Err("{{.PkgName}}: no {{.Table.Name}} provided for insertion")
 	}
 
 	var err error
@@ -37,7 +37,7 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 
 	{{if not .NoHooks -}}
 	if err := o.doBeforeInsertHooks(exec); err != nil {
-		return err
+		return errors.Err(err)
 	}
 	{{- end}}
 
@@ -59,11 +59,11 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 
 		cache.valueMapping, err = queries.BindMapping({{$varNameSingular}}Type, {{$varNameSingular}}Mapping, wl)
 		if err != nil {
-			return err
+			return errors.Err(err)
 		}
 		cache.retMapping, err = queries.BindMapping({{$varNameSingular}}Type, {{$varNameSingular}}Mapping, returnColumns)
 		if err != nil {
-			return err
+			return errors.Err(err)
 		}
 		if len(wl) != 0 {
 			cache.query = fmt.Sprintf("INSERT INTO {{$schemaTable}} ({{.LQ}}%s{{.RQ}}) %%sVALUES (%s)%%s", strings.Join(wl, "{{.RQ}},{{.LQ}}"), strmangle.Placeholders(dialect.IndexPlaceholders, len(wl), 1, 1))
@@ -110,7 +110,7 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 	_, err = exec.Exec(cache.query, vals...)
 	{{- end}}
 	if err != nil {
-		return errors.Wrap(err, "{{.PkgName}}: unable to insert into {{.Table.Name}}")
+		return errors.Prefix("{{.PkgName}}: unable to insert into {{.Table.Name}}", err)
 	}
 	
 	{{if $canLastInsertID -}}
@@ -125,7 +125,7 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 	{{if $canLastInsertID -}}
 	lastID, err = result.LastInsertId()
 	if err != nil {
-		return ErrSyncFail
+		return errors.Err(ErrSyncFail)
 	}
 
 	{{$colName := index .Table.PKey.Columns 0 -}}
@@ -150,7 +150,7 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 
 	err = exec.QueryRow(cache.retQuery, identifierCols...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...)
 	if err != nil {
-		return errors.Wrap(err, "{{.PkgName}}: unable to populate default values for {{.Table.Name}}")
+		return errors.Prefix("{{.PkgName}}: unable to populate default values for {{.Table.Name}}", err)
 	}
 	{{else}}
 	if len(cache.retMapping) != 0 {
@@ -160,7 +160,7 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
 	}
 
 	if err != nil {
-		return errors.Wrap(err, "{{.PkgName}}: unable to insert into {{.Table.Name}}")
+		return errors.Prefix("{{.PkgName}}: unable to insert into {{.Table.Name}}", err)
 	}
 	{{end}}
 
diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index bc4a6f5..eee2036 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -12,7 +12,7 @@ func (o *{{$tableNameSingular}}) UpdateG(whitelist ...string) error {
 // Panics on error. See Update for whitelist behavior description.
 func (o *{{$tableNameSingular}}) UpdateGP(whitelist ...string) {
 	if err := o.Update(boil.GetDB(), whitelist...); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -21,7 +21,7 @@ func (o *{{$tableNameSingular}}) UpdateGP(whitelist ...string) {
 func (o *{{$tableNameSingular}}) UpdateP(exec boil.Executor, whitelist ... string) {
 	err := o.Update(exec, whitelist...)
 	if err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -38,7 +38,7 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 	var err error
 	{{if not .NoHooks -}}
 	if err = o.doBeforeUpdateHooks(exec); err != nil {
-		return err
+		return errors.Err(err)
 	}
 	{{end -}}
 
@@ -62,7 +62,7 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 		}
 		{{end -}}
 		if len(wl) == 0 {
-			return errors.New("{{.PkgName}}: unable to update {{.Table.Name}}, could not build whitelist")
+			return errors.Err("{{.PkgName}}: unable to update {{.Table.Name}}, could not build whitelist")
 		}
 
 		cache.query = fmt.Sprintf("UPDATE {{$schemaTable}} SET %s WHERE %s",
@@ -71,7 +71,7 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 		)
 		cache.valueMapping, err = queries.BindMapping({{$varNameSingular}}Type, {{$varNameSingular}}Mapping, append(wl, {{$varNameSingular}}PrimaryKeyColumns...))
 		if err != nil {
-			return err
+			return errors.Err(err)
 		}
 	}
 
@@ -84,7 +84,7 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 
 	_, err = exec.Exec(cache.query, values...)
 	if err != nil {
-		return errors.Wrap(err, "{{.PkgName}}: unable to update {{.Table.Name}} row")
+		return errors.Prefix("{{.PkgName}}: unable to update {{.Table.Name}} row", err)
 	}
 
 	if !cached {
@@ -103,7 +103,7 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 // UpdateAllP updates all rows with matching column names, and panics on error.
 func (q {{$tableNameSingular}}Query) UpdateAllP(cols M) {
 	if err := q.UpdateAll(cols); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -113,7 +113,7 @@ func (q {{$tableNameSingular}}Query) UpdateAll(cols M) error {
 
 	_, err := q.Query.Exec()
 	if err != nil {
-		return errors.Wrap(err, "{{.PkgName}}: unable to update all for {{.Table.Name}}")
+		return errors.Prefix("{{.PkgName}}: unable to update all for {{.Table.Name}}", err)
 	}
 
 	return nil
@@ -127,14 +127,14 @@ func (o {{$tableNameSingular}}Slice) UpdateAllG(cols M) error {
 // UpdateAllGP updates all rows with the specified column values, and panics on error.
 func (o {{$tableNameSingular}}Slice) UpdateAllGP(cols M) {
 	if err := o.UpdateAll(boil.GetDB(), cols); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
 // UpdateAllP updates all rows with the specified column values, and panics on error.
 func (o {{$tableNameSingular}}Slice) UpdateAllP(exec boil.Executor, cols M) {
 	if err := o.UpdateAll(exec, cols); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -146,7 +146,7 @@ func (o {{$tableNameSingular}}Slice) UpdateAll(exec boil.Executor, cols M) error
 	}
 
 	if len(cols) == 0 {
-		return errors.New("{{.PkgName}}: update all requires at least one column argument")
+		return errors.Err("{{.PkgName}}: update all requires at least one column argument")
 	}
 
 	colNames := make([]string, len(cols))
@@ -176,7 +176,7 @@ func (o {{$tableNameSingular}}Slice) UpdateAll(exec boil.Executor, cols M) error
 
 	_, err := exec.Exec(sql, args...)
 	if err != nil {
-		return errors.Wrap(err, "{{.PkgName}}: unable to update all in {{$varNameSingular}} slice")
+		return errors.Prefix("{{.PkgName}}: unable to update all in {{$varNameSingular}} slice", err)
 	}
 
 	return nil
diff --git a/templates/17_upsert.tpl b/templates/17_upsert.tpl
index dbce58c..b713243 100644
--- a/templates/17_upsert.tpl
+++ b/templates/17_upsert.tpl
@@ -9,7 +9,7 @@ func (o *{{$tableNameSingular}}) UpsertG({{if eq .DriverName "postgres"}}updateO
 // UpsertGP attempts an insert, and does an update or ignore on conflict. Panics on error.
 func (o *{{$tableNameSingular}}) UpsertGP({{if eq .DriverName "postgres"}}updateOnConflict bool, conflictColumns []string, {{end}}updateColumns []string,	whitelist ...string) {
 	if err := o.Upsert(boil.GetDB(), {{if eq .DriverName "postgres"}}updateOnConflict, conflictColumns, {{end}}updateColumns, whitelist...); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -17,21 +17,21 @@ func (o *{{$tableNameSingular}}) UpsertGP({{if eq .DriverName "postgres"}}update
 // UpsertP panics on error.
 func (o *{{$tableNameSingular}}) UpsertP(exec boil.Executor, {{if eq .DriverName "postgres"}}updateOnConflict bool, conflictColumns []string, {{end}}updateColumns []string,	whitelist ...string) {
 	if err := o.Upsert(exec, {{if eq .DriverName "postgres"}}updateOnConflict, conflictColumns, {{end}}updateColumns, whitelist...); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
 // Upsert attempts an insert using an executor, and does an update or ignore on conflict.
 func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName "postgres"}}updateOnConflict bool, conflictColumns []string, {{end}}updateColumns []string, whitelist ...string) error {
 	if o == nil {
-		return errors.New("{{.PkgName}}: no {{.Table.Name}} provided for upsert")
+		return errors.Err("{{.PkgName}}: no {{.Table.Name}} provided for upsert")
 	}
 
 	{{- template "timestamp_upsert_helper" . }}
 
 	{{if not .NoHooks -}}
 	if err := o.doBeforeUpsertHooks(exec); err != nil {
-		return err
+		return errors.Err(err)
 	}
 	{{- end}}
 
@@ -87,7 +87,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 			}
 		}
 		if len(insert) == 0 {
-			return errors.New("{{.PkgName}}: unable to upsert {{.Table.Name}}, could not build insert column list")
+			return errors.Err("{{.PkgName}}: unable to upsert {{.Table.Name}}, could not build insert column list")
 		}
 
 		ret = strmangle.SetMerge(ret, {{$varNameSingular}}ColumnsWithAuto)
@@ -104,7 +104,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 		{{end -}}
 
 		if len(update) == 0 {
-			return errors.New("{{.PkgName}}: unable to upsert {{.Table.Name}}, could not build update column list")
+			return errors.Err("{{.PkgName}}: unable to upsert {{.Table.Name}}, could not build update column list")
 		}
 
 		{{if eq .DriverName "postgres"}}
@@ -129,12 +129,12 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 
 		cache.valueMapping, err = queries.BindMapping({{$varNameSingular}}Type, {{$varNameSingular}}Mapping, {{if eq .DriverName "mssql"}}whitelist{{else}}insert{{end}})
 		if err != nil {
-			return err
+			return errors.Err(err)
 		}
 		if len(ret) != 0 {
 			cache.retMapping, err = queries.BindMapping({{$varNameSingular}}Type, {{$varNameSingular}}Mapping, ret)
 			if err != nil {
-				return err
+				return errors.Err(err)
 			}
 		}
 	}
@@ -159,7 +159,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 	_, err = exec.Exec(cache.query, vals...)
 	{{- end}}
 	if err != nil {
-		return errors.Wrap(err, "{{.PkgName}}: unable to upsert for {{.Table.Name}}")
+		return errors.Prefix("{{.PkgName}}: unable to upsert for {{.Table.Name}}", err)
 	}
 
 	{{if $canLastInsertID -}}
@@ -174,7 +174,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 	{{if $canLastInsertID -}}
 	lastID, err = result.LastInsertId()
 	if err != nil {
-		return ErrSyncFail
+		return errors.Err(ErrSyncFail)
 	}
 
 	{{$colName := index .Table.PKey.Columns 0 -}}
@@ -199,7 +199,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 
 	err = exec.QueryRow(cache.retQuery, identifierCols...).Scan(returns...)
 	if err != nil {
-		return errors.Wrap(err, "{{.PkgName}}: unable to populate default values for {{.Table.Name}}")
+		return errors.Prefix("{{.PkgName}}: unable to populate default values for {{.Table.Name}}", err)
 	}
 	{{- else}}
 	if len(cache.retMapping) != 0 {
@@ -211,7 +211,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if eq .DriverName
 		_, err = exec.Exec(cache.query, vals...)
 	}
 	if err != nil {
-		return errors.Wrap(err, "{{.PkgName}}: unable to upsert {{.Table.Name}}")
+		return errors.Prefix("{{.PkgName}}: unable to upsert {{.Table.Name}}", err)
 	}
 	{{- end}}
 
diff --git a/templates/18_delete.tpl b/templates/18_delete.tpl
index aea163e..1ab82a3 100644
--- a/templates/18_delete.tpl
+++ b/templates/18_delete.tpl
@@ -6,7 +6,7 @@
 // Panics on error.
 func (o *{{$tableNameSingular}}) DeleteP(exec boil.Executor) {
 	if err := o.Delete(exec); err != nil {
-	panic(boil.WrapErr(err))
+	panic(errors.Err(err))
 	}
 }
 
@@ -14,7 +14,7 @@ func (o *{{$tableNameSingular}}) DeleteP(exec boil.Executor) {
 // DeleteG will match against the primary key column to find the record to delete.
 func (o *{{$tableNameSingular}}) DeleteG() error {
 	if o == nil {
-	  return errors.New("{{.PkgName}}: no {{$tableNameSingular}} provided for deletion")
+	  return errors.Err("{{.PkgName}}: no {{$tableNameSingular}} provided for deletion")
 	}
 
 	return o.Delete(boil.GetDB())
@@ -25,7 +25,7 @@ func (o *{{$tableNameSingular}}) DeleteG() error {
 // Panics on error.
 func (o *{{$tableNameSingular}}) DeleteGP() {
 	if err := o.DeleteG(); err != nil {
-	  panic(boil.WrapErr(err))
+	  panic(errors.Err(err))
 	}
 }
 
@@ -33,12 +33,12 @@ func (o *{{$tableNameSingular}}) DeleteGP() {
 // Delete will match against the primary key column to find the record to delete.
 func (o *{{$tableNameSingular}}) Delete(exec boil.Executor) error {
 	if o == nil {
-	  return errors.New("{{.PkgName}}: no {{$tableNameSingular}} provided for delete")
+	  return errors.Err("{{.PkgName}}: no {{$tableNameSingular}} provided for delete")
 	}
 
 	{{if not .NoHooks -}}
 	if err := o.doBeforeDeleteHooks(exec); err != nil {
-	  return err
+	  return errors.Err(err)
 	}
 	{{- end}}
 
@@ -52,12 +52,12 @@ func (o *{{$tableNameSingular}}) Delete(exec boil.Executor) error {
 
 	_, err := exec.Exec(sql, args...)
 	if err != nil {
-  	return errors.Wrap(err, "{{.PkgName}}: unable to delete from {{.Table.Name}}")
+  	return errors.Prefix("{{.PkgName}}: unable to delete from {{.Table.Name}}", err)
 	}
 
 	{{if not .NoHooks -}}
 	if err := o.doAfterDeleteHooks(exec); err != nil {
-	  return err
+	  return errors.Err(err)
 	}
 	{{- end}}
 
@@ -67,21 +67,21 @@ func (o *{{$tableNameSingular}}) Delete(exec boil.Executor) error {
 // DeleteAllP deletes all rows, and panics on error.
 func (q {{$tableNameSingular}}Query) DeleteAllP() {
 	if err := q.DeleteAll(); err != nil {
-	  panic(boil.WrapErr(err))
+	  panic(errors.Err(err))
 	}
 }
 
 // DeleteAll deletes all matching rows.
 func (q {{$tableNameSingular}}Query) DeleteAll() error {
 	if q.Query == nil {
-	  return errors.New("{{.PkgName}}: no {{$tableNameSingular}}Query provided for delete all")
+	  return errors.Err("{{.PkgName}}: no {{$tableNameSingular}}Query provided for delete all")
 	}
 
 	queries.SetDelete(q.Query)
 
 	_, err := q.Query.Exec()
 	if err != nil {
-	  return errors.Wrap(err, "{{.PkgName}}: unable to delete all from {{.Table.Name}}")
+	  return errors.Prefix("{{.PkgName}}: unable to delete all from {{.Table.Name}}", err)
 	}
 
 	return nil
@@ -90,14 +90,14 @@ func (q {{$tableNameSingular}}Query) DeleteAll() error {
 // DeleteAllGP deletes all rows in the slice, and panics on error.
 func (o {{$tableNameSingular}}Slice) DeleteAllGP() {
 	if err := o.DeleteAllG(); err != nil {
-	  panic(boil.WrapErr(err))
+	  panic(errors.Err(err))
 	}
 }
 
 // DeleteAllG deletes all rows in the slice.
 func (o {{$tableNameSingular}}Slice) DeleteAllG() error {
 	if o == nil {
-	  return errors.New("{{.PkgName}}: no {{$tableNameSingular}} slice provided for delete all")
+	  return errors.Err("{{.PkgName}}: no {{$tableNameSingular}} slice provided for delete all")
 	}
 	return o.DeleteAll(boil.GetDB())
 }
@@ -105,14 +105,14 @@ func (o {{$tableNameSingular}}Slice) DeleteAllG() error {
 // DeleteAllP deletes all rows in the slice, using an executor, and panics on error.
 func (o {{$tableNameSingular}}Slice) DeleteAllP(exec boil.Executor) {
 	if err := o.DeleteAll(exec); err != nil {
-	  panic(boil.WrapErr(err))
+	  panic(errors.Err(err))
 	}
 }
 
 // DeleteAll deletes all rows in the slice, using an executor.
 func (o {{$tableNameSingular}}Slice) DeleteAll(exec boil.Executor) error {
 	if o == nil {
-		return errors.New("{{.PkgName}}: no {{$tableNameSingular}} slice provided for delete all")
+		return errors.Err("{{.PkgName}}: no {{$tableNameSingular}} slice provided for delete all")
 	}
 
 	if len(o) == 0 {
@@ -123,7 +123,7 @@ func (o {{$tableNameSingular}}Slice) DeleteAll(exec boil.Executor) error {
 	if len({{$varNameSingular}}BeforeDeleteHooks) != 0 {
 		for _, obj := range o {
 			if err := obj.doBeforeDeleteHooks(exec); err != nil {
-				return err
+				return errors.Err(err)
 			}
 		}
 	}
@@ -145,14 +145,14 @@ func (o {{$tableNameSingular}}Slice) DeleteAll(exec boil.Executor) error {
 
 	_, err := exec.Exec(sql, args...)
 	if err != nil {
-		return errors.Wrap(err, "{{.PkgName}}: unable to delete all from {{$varNameSingular}} slice")
+		return errors.Prefix("{{.PkgName}}: unable to delete all from {{$varNameSingular}} slice", err)
 	}
 
 	{{if not .NoHooks -}}
 	if len({{$varNameSingular}}AfterDeleteHooks) != 0 {
 		for _, obj := range o {
 			if err := obj.doAfterDeleteHooks(exec); err != nil {
-				return err
+				return errors.Err(err)
 			}
 		}
 	}
diff --git a/templates/19_reload.tpl b/templates/19_reload.tpl
index b1201b8..c7c5273 100644
--- a/templates/19_reload.tpl
+++ b/templates/19_reload.tpl
@@ -5,21 +5,21 @@
 // ReloadGP refetches the object from the database and panics on error.
 func (o *{{$tableNameSingular}}) ReloadGP() {
 	if err := o.ReloadG(); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
 // ReloadP refetches the object from the database with an executor. Panics on error.
 func (o *{{$tableNameSingular}}) ReloadP(exec boil.Executor) {
 	if err := o.Reload(exec); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
 // ReloadG refetches the object from the database using the primary keys.
 func (o *{{$tableNameSingular}}) ReloadG() error {
 	if o == nil {
-		return errors.New("{{.PkgName}}: no {{$tableNameSingular}} provided for reload")
+		return errors.Err("{{.PkgName}}: no {{$tableNameSingular}} provided for reload")
 	}
 
 	return o.Reload(boil.GetDB())
@@ -30,7 +30,7 @@ func (o *{{$tableNameSingular}}) ReloadG() error {
 func (o *{{$tableNameSingular}}) Reload(exec boil.Executor) error {
 	ret, err := Find{{$tableNameSingular}}(exec, {{.Table.PKey.Columns | stringMap .StringFuncs.titleCase | prefixStringSlice "o." | join ", "}})
 	if err != nil {
-		return err
+		return errors.Err(err)
 	}
 
 	*o = *ret
@@ -42,7 +42,7 @@ func (o *{{$tableNameSingular}}) Reload(exec boil.Executor) error {
 // Panics on error.
 func (o *{{$tableNameSingular}}Slice) ReloadAllGP() {
 	if err := o.ReloadAllG(); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -51,7 +51,7 @@ func (o *{{$tableNameSingular}}Slice) ReloadAllGP() {
 // Panics on error.
 func (o *{{$tableNameSingular}}Slice) ReloadAllP(exec boil.Executor) {
 	if err := o.ReloadAll(exec); err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 }
 
@@ -59,7 +59,7 @@ func (o *{{$tableNameSingular}}Slice) ReloadAllP(exec boil.Executor) {
 // and overwrites the original object slice with the newly updated slice.
 func (o *{{$tableNameSingular}}Slice) ReloadAllG() error {
 	if o == nil {
-		return errors.New("{{.PkgName}}: empty {{$tableNameSingular}}Slice provided for reload all")
+		return errors.Err("{{.PkgName}}: empty {{$tableNameSingular}}Slice provided for reload all")
 	}
 
 	return o.ReloadAll(boil.GetDB())
@@ -86,7 +86,7 @@ func (o *{{$tableNameSingular}}Slice) ReloadAll(exec boil.Executor) error {
 
 	err := q.Bind(&{{$varNamePlural}})
 	if err != nil {
-		return errors.Wrap(err, "{{.PkgName}}: unable to reload all in {{$tableNameSingular}}Slice")
+		return errors.Prefix("{{.PkgName}}: unable to reload all in {{$tableNameSingular}}Slice", err)
 	}
 
 	*o = {{$varNamePlural}}
diff --git a/templates/20_exists.tpl b/templates/20_exists.tpl
index 2e20fa6..2a36c23 100644
--- a/templates/20_exists.tpl
+++ b/templates/20_exists.tpl
@@ -22,7 +22,7 @@ func {{$tableNameSingular}}Exists(exec boil.Executor, {{$pkArgs}}) (bool, error)
 
 	err := row.Scan(&exists)
 	if err != nil {
-		return false, errors.Wrap(err, "{{.PkgName}}: unable to check if {{.Table.Name}} exists")
+		return false, errors.Prefix("{{.PkgName}}: unable to check if {{.Table.Name}} exists", err)
 	}
 
 	return exists, nil
@@ -37,7 +37,7 @@ func {{$tableNameSingular}}ExistsG({{$pkArgs}}) (bool, error) {
 func {{$tableNameSingular}}ExistsGP({{$pkArgs}}) bool {
 	e, err := {{$tableNameSingular}}Exists(boil.GetDB(), {{$pkNames | join ", "}})
 	if err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 
 	return e
@@ -47,7 +47,7 @@ func {{$tableNameSingular}}ExistsGP({{$pkArgs}}) bool {
 func {{$tableNameSingular}}ExistsP(exec boil.Executor, {{$pkArgs}}) bool {
 	e, err := {{$tableNameSingular}}Exists(exec, {{$pkNames | join ", "}})
 	if err != nil {
-		panic(boil.WrapErr(err))
+		panic(errors.Err(err))
 	}
 
 	return e
diff --git a/templates/23_merge.tpl b/templates/23_merge.tpl
index 9f1af10..16a7b58 100644
--- a/templates/23_merge.tpl
+++ b/templates/23_merge.tpl
@@ -9,12 +9,12 @@ func Merge{{$tableNamePlural}}(exec boil.Executor, primaryID uint64, secondaryID
 	if !ok {
 		txdb, ok := exec.(boil.Beginner)
 		if !ok {
-			return errors.New("database does not support transactions")
+			return errors.Err("database does not support transactions")
 		}
 
 		tx, err = txdb.Begin()
 		if err != nil {
-			return err
+			return errors.Err(err)
 		}
 
 		defer func() {
@@ -31,16 +31,16 @@ func Merge{{$tableNamePlural}}(exec boil.Executor, primaryID uint64, secondaryID
 
   primary, err := Find{{$tableNameSingular}}(tx, primaryID)
   if err != nil {
-    return err
+    return errors.Err(err)
   } else if primary == nil {
-		return errors.New("Primary {{$tableNameSingular}} not found")
+		return errors.Err("primary {{$tableNameSingular}} not found")
 	}
 
   secondary, err := Find{{$tableNameSingular}}(tx, secondaryID)
   if err != nil {
-    return err
+    return errors.Err(err)
   } else if secondary == nil {
-		return errors.New("Secondary {{$tableNameSingular}} not found")
+		return errors.Err("secondary {{$tableNameSingular}} not found")
 	}
 
   foreignKeys := []foreignKey{
@@ -89,12 +89,12 @@ func Merge{{$tableNamePlural}}(exec boil.Executor, primaryID uint64, secondaryID
 
 	err = primary.Update(tx)
 	if err != nil {
-		return errors.WithStack(err)
+		return err
 	}
 
 	err = secondary.Delete(tx)
 	if err != nil {
-		return errors.WithStack(err)
+		return err
 	}
 
   return nil
diff --git a/templates/singleton/boil_queries.tpl b/templates/singleton/boil_queries.tpl
index 1260dde..51ed108 100644
--- a/templates/singleton/boil_queries.tpl
+++ b/templates/singleton/boil_queries.tpl
@@ -29,7 +29,7 @@ func mergeModels(tx boil.Executor, primaryID uint64, secondaryID uint64, foreign
 	for _, conflict := range conflictingKeys {
 		err = deleteConflictsBeforeMerge(tx, conflict, primaryID, secondaryID)
 		if err != nil {
-			return errors.WithStack(err)
+			return err
 		}
 	}
 
@@ -42,7 +42,7 @@ func mergeModels(tx boil.Executor, primaryID uint64, secondaryID uint64, foreign
 		)
 		_, err = tx.Exec(query, primaryID, secondaryID)
 		if err != nil {
-			return errors.WithStack(err)
+			return errors.Err(err)
 		}
 	}
 	return checkMerge(tx, foreignKeys)
@@ -54,7 +54,7 @@ func deleteConflictsBeforeMerge(tx boil.Executor, conflict conflictingUniqueKey,
 	if len(conflictingColumns) < 1 {
 		return nil
 	} else if len(conflictingColumns) > 1 {
-		return errors.New("this doesnt work for unique keys with more than two columns (yet)")
+		return errors.Err("this doesnt work for unique keys with more than two columns (yet)")
 	}
 
 	query := fmt.Sprintf(
@@ -67,7 +67,7 @@ func deleteConflictsBeforeMerge(tx boil.Executor, conflict conflictingUniqueKey,
 	rows, err := tx.Query(query, primaryID, secondaryID)
 	defer rows.Close()
 	if err != nil {
-		return errors.WithStack(err)
+		return errors.Err(err)
 	}
 
 	args := []interface{}{secondaryID}
@@ -75,7 +75,7 @@ func deleteConflictsBeforeMerge(tx boil.Executor, conflict conflictingUniqueKey,
 		var value string
 		err = rows.Scan(&value)
 		if err != nil {
-			return errors.WithStack(err)
+			return errors.Err(err)
 		}
 		args = append(args, value)
 	}
@@ -93,7 +93,7 @@ func deleteConflictsBeforeMerge(tx boil.Executor, conflict conflictingUniqueKey,
 
 	_, err = tx.Exec(query, args...)
 	if err != nil {
-		return errors.WithStack(err)
+		return errors.Err(err)
 	}
 	return nil
 }
@@ -118,7 +118,7 @@ func checkMerge(tx boil.Executor, foreignKeys []foreignKey) error {
 	rows, err := tx.Query(q, uniqueColumns...)
 	defer rows.Close()
 	if err != nil {
-		return errors.WithStack(err)
+		return errors.Err(err)
 	}
 
 	for rows.Next() {
@@ -126,11 +126,11 @@ func checkMerge(tx boil.Executor, foreignKeys []foreignKey) error {
 		var columnName string
 		err = rows.Scan(&tableName, &columnName)
 		if err != nil {
-			return errors.WithStack(err)
+			return errors.Err(err)
 		}
 
 		if _, exists := handledTablesColumns[tableName+"."+columnName]; !exists {
-			return errors.New("Missing merge for " + tableName + "." + columnName)
+			return errors.Err("missing merge for " + tableName + "." + columnName)
 		}
 	}
 
diff --git a/templates/singleton/boil_types.tpl b/templates/singleton/boil_types.tpl
index 547d05d..48a85e2 100644
--- a/templates/singleton/boil_types.tpl
+++ b/templates/singleton/boil_types.tpl
@@ -20,7 +20,7 @@ type conflictingUniqueKey struct {
 // ErrSyncFail occurs during insert when the record could not be retrieved in
 // order to populate default value information. This usually happens when LastInsertId
 // fails or there was a primary key configuration that was not resolvable.
-var ErrSyncFail = errors.New("{{.PkgName}}: failed to synchronize data after insert")
+var ErrSyncFail = errors.Base("{{.PkgName}}: failed to synchronize data after insert")
 
 type insertCache struct {
 	query        string
diff --git a/templates_test/main_test/mssql_main.tpl b/templates_test/main_test/mssql_main.tpl
index ba46be7..5b0b5e1 100644
--- a/templates_test/main_test/mssql_main.tpl
+++ b/templates_test/main_test/mssql_main.tpl
@@ -25,17 +25,17 @@ func (m *mssqlTester) setup() error {
 	m.testDBName = randomize.StableDBName(m.dbName)
 
 	if err = m.dropTestDB(); err != nil {
-		return err
+		return errors.Err(err)
 	}
 	if err = m.createTestDB(); err != nil {
-		return err
+		return errors.Err(err)
 	}
 
 	createCmd := exec.Command("sqlcmd", "-S", m.host, "-U", m.user, "-P", m.pass, "-d", m.testDBName)
 
 	f, err := os.Open("tables_schema.sql")
 	if err != nil {
-		return errors.Wrap(err, "failed to open tables_schema.sql file")
+		return errors.Prefix("failed to open tables_schema.sql file", err)
 	}
 
 	defer f.Close()
@@ -43,12 +43,12 @@ func (m *mssqlTester) setup() error {
 	createCmd.Stdin = newFKeyDestroyer(rgxMSSQLkey, f)
 
 	if err = createCmd.Start(); err != nil {
-		return errors.Wrap(err, "failed to start sqlcmd command")
+		return errors.Prefix("failed to start sqlcmd command", err)
 	}
 
 	if err = createCmd.Wait(); err != nil {
 		fmt.Println(err)
-		return errors.Wrap(err, "failed to wait for sqlcmd command")
+		return errors.Prefix("failed to wait for sqlcmd command", err)
 	}
 
 	return nil
@@ -92,7 +92,7 @@ func (m *mssqlTester) teardown() error {
 	}
 
 	if err := m.dropTestDB(); err != nil {
-		return err
+		return errors.Err(err)
 	}
 
 	return nil
@@ -110,7 +110,7 @@ func (m *mssqlTester) runCmd(stdin, command string, args ...string) error {
 		fmt.Println("failed running:", command, args)
 		fmt.Println(stdout.String())
 		fmt.Println(stderr.String())
-		return err
+		return errors.Err(err)
 	}
 
 	return nil
diff --git a/templates_test/main_test/mysql_main.tpl b/templates_test/main_test/mysql_main.tpl
index b95b32c..ef735e2 100644
--- a/templates_test/main_test/mysql_main.tpl
+++ b/templates_test/main_test/mysql_main.tpl
@@ -30,14 +30,14 @@ func (m *mysqlTester) setup() error {
 	m.testDBName = randomize.StableDBName(m.dbName)
 
 	if err = m.makeOptionFile(); err != nil {
-		return errors.Wrap(err, "couldn't make option file")
+		return errors.Prefix("couldn't make option file", err)
 	}
 
 	if err = m.dropTestDB(); err != nil {
-		return err
+		return errors.Err(err)
 	}
 	if err = m.createTestDB(); err != nil {
-		return err
+		return errors.Err(err)
 	}
 
 	dumpCmd := exec.Command("mysqldump", m.defaultsFile(), "--no-data", m.dbName)
@@ -48,22 +48,22 @@ func (m *mysqlTester) setup() error {
 	createCmd.Stdin = newFKeyDestroyer(rgxMySQLkey, r)
 
 	if err = dumpCmd.Start(); err != nil {
-		return errors.Wrap(err, "failed to start mysqldump command")
+		return errors.Prefix("failed to start mysqldump command", err)
 	}
 	if err = createCmd.Start(); err != nil {
-		return errors.Wrap(err, "failed to start mysql command")
+		return errors.Prefix("failed to start mysql command", err)
 	}
 
 	if err = dumpCmd.Wait(); err != nil {
 		fmt.Println(err)
-		return errors.Wrap(err, "failed to wait for mysqldump command")
+		return errors.Prefix("failed to wait for mysqldump command", err)
 	}
 
 	w.Close() // After dumpCmd is done, close the write end of the pipe
 
 	if err = createCmd.Wait(); err != nil {
 		fmt.Println(err)
-		return errors.Wrap(err, "failed to wait for mysql command")
+		return errors.Prefix("failed to wait for mysql command", err)
 	}
 
 	return nil
@@ -87,7 +87,7 @@ func (m *mysqlTester) defaultsFile() string {
 func (m *mysqlTester) makeOptionFile() error {
 	tmp, err := ioutil.TempFile("", "optionfile")
 	if err != nil {
-		return errors.Wrap(err, "failed to create option file")
+		return errors.Prefix("failed to create option file", err)
 	}
 
 	isTCP := false
@@ -95,7 +95,7 @@ func (m *mysqlTester) makeOptionFile() error {
 	if os.IsNotExist(err) {
 		isTCP = true
 	} else if err != nil {
-		return errors.Wrap(err, "could not stat m.host")
+		return errors.Prefix("could not stat m.host", err)
 	}
 
 	fmt.Fprintln(tmp, "[client]")
@@ -139,7 +139,7 @@ func (m *mysqlTester) teardown() error {
 	}
 
 	if err := m.dropTestDB(); err != nil {
-		return err
+		return errors.Err(err)
 	}
 
 	return os.Remove(m.optionFile)
@@ -159,7 +159,7 @@ func (m *mysqlTester) runCmd(stdin, command string, args ...string) error {
 	fmt.Println("failed running:", command, args)
 	fmt.Println(stdout.String())
 	fmt.Println(stderr.String())
-	return err
+	return errors.Err(err)
 	}
 
 	return nil
diff --git a/templates_test/main_test/postgres_main.tpl b/templates_test/main_test/postgres_main.tpl
index 0abcba3..3110325 100644
--- a/templates_test/main_test/postgres_main.tpl
+++ b/templates_test/main_test/postgres_main.tpl
@@ -33,14 +33,14 @@ func (p *pgTester) setup() error {
   p.testDBName = randomize.StableDBName(p.dbName)
 
   if err = p.makePGPassFile(); err != nil {
-    return err
+    return errors.Err(err)
   }
 
   if err = p.dropTestDB(); err != nil {
-    return err
+    return errors.Err(err)
   }
   if err = p.createTestDB(); err != nil {
-    return err
+    return errors.Err(err)
   }
 
   dumpCmd := exec.Command("pg_dump", "--schema-only", p.dbName)
@@ -53,22 +53,22 @@ func (p *pgTester) setup() error {
   createCmd.Stdin = newFKeyDestroyer(rgxPGFkey, r)
 
   if err = dumpCmd.Start(); err != nil {
-    return errors.Wrap(err, "failed to start pg_dump command")
+    return errors.Prefix("failed to start pg_dump command", err)
   }
   if err = createCmd.Start(); err != nil {
-    return errors.Wrap(err, "failed to start psql command")
+    return errors.Prefix("failed to start psql command", err)
   }
 
   if err = dumpCmd.Wait(); err != nil {
     fmt.Println(err)
-    return errors.Wrap(err, "failed to wait for pg_dump command")
+    return errors.Prefix("failed to wait for pg_dump command", err)
   }
 
   w.Close() // After dumpCmd is done, close the write end of the pipe
 
   if err = createCmd.Wait(); err != nil {
     fmt.Println(err)
-    return errors.Wrap(err, "failed to wait for psql command")
+    return errors.Prefix("failed to wait for psql command", err)
   }
 
   return nil
@@ -90,7 +90,7 @@ func (p *pgTester) runCmd(stdin, command string, args ...string) error {
     fmt.Println("failed running:", command, args)
     fmt.Println(stdout.String())
     fmt.Println(stderr.String())
-    return err
+    return errors.Err(err)
   }
 
   return nil
@@ -108,7 +108,7 @@ func (p *pgTester) pgEnv() []string {
 func (p *pgTester) makePGPassFile() error {
   tmp, err := ioutil.TempFile("", "pgpass")
   if err != nil {
-    return errors.Wrap(err, "failed to create option file")
+    return errors.Prefix("failed to create option file", err)
   }
 
   fmt.Fprintf(tmp, "%s:%d:postgres:%s", p.host, p.port, p.user)
@@ -145,12 +145,12 @@ func (p *pgTester) dropTestDB() error {
 func (p *pgTester) teardown() error {
   var err error
   if err = p.dbConn.Close(); err != nil {
-    return err
+    return errors.Err(err)
   }
   p.dbConn = nil
 
   if err = p.dropTestDB(); err != nil {
-    return err
+    return errors.Err(err)
   }
 
   return os.Remove(p.pgPassFile)
diff --git a/templates_test/singleton/boil_main_test.tpl b/templates_test/singleton/boil_main_test.tpl
index ebb4758..3cf466d 100644
--- a/templates_test/singleton/boil_main_test.tpl
+++ b/templates_test/singleton/boil_main_test.tpl
@@ -143,5 +143,5 @@ func validateConfig(driverName string) error {
 		).Check()
 	}
 
-	return errors.New("not a valid driver name")
+	return errors.Err("not a valid driver name")
 }

From 77fc991e7b786a1b1f373a274ff5e6457e43f2df Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Thu, 22 Feb 2018 13:18:41 -0500
Subject: [PATCH 168/179] new location for null.go

---
 boilingcore/imports.go      | 50 ++++++++++++++++++-------------------
 boilingcore/imports_test.go | 10 ++++----
 queries/helpers_test.go     |  2 +-
 queries/query.go            |  2 +-
 randomize/randomize.go      |  2 +-
 randomize/randomize_test.go |  2 +-
 6 files changed, 34 insertions(+), 34 deletions(-)

diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index b73b429..9a5c656 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -170,8 +170,8 @@ func newImporter() importer {
 			`"time"`,
 		},
 		thirdParty: importList{
-			`"github.com/lbryio/errors.go"`,
-			`"github.com/lbryio/null.go"`,
+			`"github.com/lbryio/lbry.go/errors"`,
+			`"github.com/lbryio/lbry.go/null"`,
 			`"github.com/lbryio/sqlboiler/boil"`,
 			`"github.com/lbryio/sqlboiler/queries"`,
 			`"github.com/lbryio/sqlboiler/queries/qm"`,
@@ -185,7 +185,7 @@ func newImporter() importer {
 				`"fmt"`,
 			},
 			thirdParty: importList{
-				`"github.com/lbryio/errors.go"`,
+				`"github.com/lbryio/lbry.go/errors"`,
 				`"github.com/lbryio/sqlboiler/boil"`,
 				`"github.com/lbryio/sqlboiler/queries"`,
 				`"github.com/lbryio/sqlboiler/queries/qm"`,
@@ -194,7 +194,7 @@ func newImporter() importer {
 		},
 		"boil_types": {
 			thirdParty: importList{
-				`"github.com/lbryio/errors.go"`,
+				`"github.com/lbryio/lbry.go/errors"`,
 				`"github.com/lbryio/sqlboiler/strmangle"`,
 			},
 		},
@@ -227,7 +227,7 @@ func newImporter() importer {
 			},
 			thirdParty: importList{
 				`"github.com/kat-co/vala"`,
-				`"github.com/lbryio/errors.go"`,
+				`"github.com/lbryio/lbry.go/errors"`,
 				`"github.com/lbryio/sqlboiler/boil"`,
 				`"github.com/spf13/viper"`,
 			},
@@ -265,7 +265,7 @@ func newImporter() importer {
 				`"strings"`,
 			},
 			thirdParty: importList{
-				`"github.com/lbryio/errors.go"`,
+				`"github.com/lbryio/lbry.go/errors"`,
 				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
 				`"github.com/lbryio/sqlboiler/randomize"`,
 				`_ "github.com/lib/pq"`,
@@ -285,7 +285,7 @@ func newImporter() importer {
 			},
 			thirdParty: importList{
 				`_ "github.com/go-sql-driver/mysql"`,
-				`"github.com/lbryio/errors.go"`,
+				`"github.com/lbryio/lbry.go/errors"`,
 				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
 				`"github.com/lbryio/sqlboiler/randomize"`,
 				`"github.com/spf13/viper"`,
@@ -302,7 +302,7 @@ func newImporter() importer {
 			},
 			thirdParty: importList{
 				`_ "github.com/denisenkom/go-mssqldb"`,
-				`"github.com/lbryio/errors.go"`,
+				`"github.com/lbryio/lbry.go/errors"`,
 				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
 				`"github.com/lbryio/sqlboiler/randomize"`,
 				`"github.com/spf13/viper"`,
@@ -315,55 +315,55 @@ func newImporter() importer {
 	// TranslateColumnType to see the type assignments.
 	imp.BasedOnType = mapImports{
 		"null.Float32": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Float64": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Int": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Int8": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Int16": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Int32": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Int64": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Uint": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Uint8": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Uint16": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Uint32": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Uint64": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.String": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Bool": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Time": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.JSON": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"null.Bytes": {
-			thirdParty: importList{`"github.com/lbryio/null.go"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
 		},
 		"time.Time": {
 			standard: importList{`"time"`},
diff --git a/boilingcore/imports_test.go b/boilingcore/imports_test.go
index b25eece..693bc10 100644
--- a/boilingcore/imports_test.go
+++ b/boilingcore/imports_test.go
@@ -246,7 +246,7 @@ func TestCombineTypeImports(t *testing.T) {
 		},
 		thirdParty: importList{
 			`"github.com/lbryio/sqlboiler/boil"`,
-			`"github.com/lbryio/null.go"`,
+			`"github.com/lbryio/lbry.go/null"`,
 		},
 	}
 
@@ -281,7 +281,7 @@ func TestCombineTypeImports(t *testing.T) {
 		},
 		thirdParty: importList{
 			`"github.com/lbryio/sqlboiler/boil"`,
-			`"github.com/lbryio/null.go"`,
+			`"github.com/lbryio/lbry.go/null"`,
 		},
 	}
 
@@ -297,7 +297,7 @@ func TestCombineImports(t *testing.T) {
 
 	a := imports{
 		standard:   importList{"fmt"},
-		thirdParty: importList{"github.com/lbryio/sqlboiler", "github.com/lbryio/null.go"},
+		thirdParty: importList{"github.com/lbryio/sqlboiler", "github.com/lbryio/lbry.go/null"},
 	}
 	b := imports{
 		standard:   importList{"os"},
@@ -309,8 +309,8 @@ func TestCombineImports(t *testing.T) {
 	if c.standard[0] != "fmt" && c.standard[1] != "os" {
 		t.Errorf("Wanted: fmt, os got: %#v", c.standard)
 	}
-	if c.thirdParty[0] != "github.com/lbryio/sqlboiler" && c.thirdParty[1] != "github.com/lbryio/null.go" {
-		t.Errorf("Wanted: github.com/lbryio/sqlboiler, github.com/lbryio/null.go got: %#v", c.thirdParty)
+	if c.thirdParty[0] != "github.com/lbryio/sqlboiler" && c.thirdParty[1] != "github.com/lbryio/lbry.go/null" {
+		t.Errorf("Wanted: github.com/lbryio/sqlboiler, github.com/lbryio/lbry.go/null got: %#v", c.thirdParty)
 	}
 }
 
diff --git a/queries/helpers_test.go b/queries/helpers_test.go
index ab4b4ac..b6b757d 100644
--- a/queries/helpers_test.go
+++ b/queries/helpers_test.go
@@ -5,7 +5,7 @@ import (
 	"testing"
 	"time"
 
-	null "github.com/lbryio/null.go"
+	null "github.com/lbryio/lbry.go/null"
 )
 
 type testObj struct {
diff --git a/queries/query.go b/queries/query.go
index a76c046..fdd54b4 100644
--- a/queries/query.go
+++ b/queries/query.go
@@ -4,7 +4,7 @@ import (
 	"database/sql"
 	"fmt"
 
-	"github.com/lbryio/errors.go"
+	"github.com/lbryio/lbry.go/errors"
 	"github.com/lbryio/sqlboiler/boil"
 )
 
diff --git a/randomize/randomize.go b/randomize/randomize.go
index 8deb88d..54c88bf 100644
--- a/randomize/randomize.go
+++ b/randomize/randomize.go
@@ -14,7 +14,7 @@ import (
 	"sync/atomic"
 	"time"
 
-	null "github.com/lbryio/null.go"
+	null "github.com/lbryio/lbry.go/null"
 
 	"github.com/pkg/errors"
 	"github.com/satori/go.uuid"
diff --git a/randomize/randomize_test.go b/randomize/randomize_test.go
index ccef115..bc7a382 100644
--- a/randomize/randomize_test.go
+++ b/randomize/randomize_test.go
@@ -5,7 +5,7 @@ import (
 	"testing"
 	"time"
 
-	null "github.com/lbryio/null.go"
+	null "github.com/lbryio/lbry.go/null"
 )
 
 func TestRandomizeStruct(t *testing.T) {

From 396f42bc91eec4d95f3dc1c5180a863175824033 Mon Sep 17 00:00:00 2001
From: Alex Grintsvayg <git@grin.io>
Date: Mon, 16 Apr 2018 12:41:55 -0400
Subject: [PATCH 169/179] never update created_at, updated_at columns

---
 templates/16_update.tpl | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/templates/16_update.tpl b/templates/16_update.tpl
index eee2036..a4a688c 100644
--- a/templates/16_update.tpl
+++ b/templates/16_update.tpl
@@ -56,11 +56,9 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
 		{{if eq .DriverName "mssql"}}
 		wl = strmangle.SetComplement(wl, {{$varNameSingular}}ColumnsWithAuto)
 		{{end}}
-		{{if not .NoAutoTimestamps}}
 		if len(whitelist) == 0 {
-			wl = strmangle.SetComplement(wl, []string{"created_at"})
+			wl = strmangle.SetComplement(wl, []string{"created_at","updated_at"})
 		}
-		{{end -}}
 		if len(wl) == 0 {
 			return errors.Err("{{.PkgName}}: unable to update {{.Table.Name}}, could not build whitelist")
 		}

From 8d4055e3eb1c18919978c53522a64d70139c43d1 Mon Sep 17 00:00:00 2001
From: Mark Beamer Jr <markbeamerjr@gmail.com>
Date: Wed, 6 Jun 2018 18:26:33 -0400
Subject: [PATCH 170/179] reverted default to native password authentication.

---
 bdb/drivers/mysql.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/bdb/drivers/mysql.go b/bdb/drivers/mysql.go
index dec80e0..19855fb 100644
--- a/bdb/drivers/mysql.go
+++ b/bdb/drivers/mysql.go
@@ -53,6 +53,7 @@ func MySQLBuildQueryString(user, pass, dbname, host string, port int, sslmode st
 	}
 	config.Addr += ":" + strconv.Itoa(port)
 	config.TLSConfig = sslmode
+	config.AllowNativePasswords = false
 
 	// MySQL is a bad, and by default reads date/datetime into a []byte
 	// instead of a time.Time. Tell it to stop being a bad.

From 466f2d5b2c6a8f8996b1b2136e5807767625ce6f Mon Sep 17 00:00:00 2001
From: Mark Beamer Jr <markbeamerjr@gmail.com>
Date: Wed, 6 Jun 2018 19:03:50 -0400
Subject: [PATCH 171/179] make it true

---
 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 19855fb..5523a6b 100644
--- a/bdb/drivers/mysql.go
+++ b/bdb/drivers/mysql.go
@@ -53,7 +53,7 @@ func MySQLBuildQueryString(user, pass, dbname, host string, port int, sslmode st
 	}
 	config.Addr += ":" + strconv.Itoa(port)
 	config.TLSConfig = sslmode
-	config.AllowNativePasswords = false
+	config.AllowNativePasswords = true
 
 	// MySQL is a bad, and by default reads date/datetime into a []byte
 	// instead of a time.Time. Tell it to stop being a bad.

From 3baa9e72ca1cc55c8a8fb870190861ae56d9a8a1 Mon Sep 17 00:00:00 2001
From: Mark Beamer Jr <markbeamerjr@gmail.com>
Date: Thu, 10 Jan 2019 20:11:42 -0500
Subject: [PATCH 172/179] Updated to use the latest lbry.go changes

---
 boilingcore/imports.go      | 50 ++++++++++++++++++-------------------
 boilingcore/imports_test.go | 10 ++++----
 queries/helpers_test.go     |  2 +-
 queries/query.go            |  2 +-
 randomize/randomize.go      |  2 +-
 randomize/randomize_test.go |  2 +-
 6 files changed, 34 insertions(+), 34 deletions(-)

diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index 9a5c656..b5979e3 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -170,8 +170,8 @@ func newImporter() importer {
 			`"time"`,
 		},
 		thirdParty: importList{
-			`"github.com/lbryio/lbry.go/errors"`,
-			`"github.com/lbryio/lbry.go/null"`,
+			`"github.com/lbryio/lbry.go/extras/errors"`,
+			`"github.com/lbryio/lbry.go/extras/null"`,
 			`"github.com/lbryio/sqlboiler/boil"`,
 			`"github.com/lbryio/sqlboiler/queries"`,
 			`"github.com/lbryio/sqlboiler/queries/qm"`,
@@ -185,7 +185,7 @@ func newImporter() importer {
 				`"fmt"`,
 			},
 			thirdParty: importList{
-				`"github.com/lbryio/lbry.go/errors"`,
+				`"github.com/lbryio/lbry.go/extras/errors"`,
 				`"github.com/lbryio/sqlboiler/boil"`,
 				`"github.com/lbryio/sqlboiler/queries"`,
 				`"github.com/lbryio/sqlboiler/queries/qm"`,
@@ -194,7 +194,7 @@ func newImporter() importer {
 		},
 		"boil_types": {
 			thirdParty: importList{
-				`"github.com/lbryio/lbry.go/errors"`,
+				`"github.com/lbryio/lbry.go/extras/errors"`,
 				`"github.com/lbryio/sqlboiler/strmangle"`,
 			},
 		},
@@ -227,7 +227,7 @@ func newImporter() importer {
 			},
 			thirdParty: importList{
 				`"github.com/kat-co/vala"`,
-				`"github.com/lbryio/lbry.go/errors"`,
+				`"github.com/lbryio/lbry.go/extras/errors"`,
 				`"github.com/lbryio/sqlboiler/boil"`,
 				`"github.com/spf13/viper"`,
 			},
@@ -265,7 +265,7 @@ func newImporter() importer {
 				`"strings"`,
 			},
 			thirdParty: importList{
-				`"github.com/lbryio/lbry.go/errors"`,
+				`"github.com/lbryio/lbry.go/extras/errors"`,
 				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
 				`"github.com/lbryio/sqlboiler/randomize"`,
 				`_ "github.com/lib/pq"`,
@@ -285,7 +285,7 @@ func newImporter() importer {
 			},
 			thirdParty: importList{
 				`_ "github.com/go-sql-driver/mysql"`,
-				`"github.com/lbryio/lbry.go/errors"`,
+				`"github.com/lbryio/lbry.go/extras/errors"`,
 				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
 				`"github.com/lbryio/sqlboiler/randomize"`,
 				`"github.com/spf13/viper"`,
@@ -302,7 +302,7 @@ func newImporter() importer {
 			},
 			thirdParty: importList{
 				`_ "github.com/denisenkom/go-mssqldb"`,
-				`"github.com/lbryio/lbry.go/errors"`,
+				`"github.com/lbryio/lbry.go/extras/errors"`,
 				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
 				`"github.com/lbryio/sqlboiler/randomize"`,
 				`"github.com/spf13/viper"`,
@@ -315,55 +315,55 @@ func newImporter() importer {
 	// TranslateColumnType to see the type assignments.
 	imp.BasedOnType = mapImports{
 		"null.Float32": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Float64": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Int": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Int8": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Int16": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Int32": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Int64": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Uint": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Uint8": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Uint16": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Uint32": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Uint64": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.String": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Bool": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Time": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.JSON": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"null.Bytes": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
 		},
 		"time.Time": {
 			standard: importList{`"time"`},
diff --git a/boilingcore/imports_test.go b/boilingcore/imports_test.go
index 693bc10..6d22956 100644
--- a/boilingcore/imports_test.go
+++ b/boilingcore/imports_test.go
@@ -246,7 +246,7 @@ func TestCombineTypeImports(t *testing.T) {
 		},
 		thirdParty: importList{
 			`"github.com/lbryio/sqlboiler/boil"`,
-			`"github.com/lbryio/lbry.go/null"`,
+			`"github.com/lbryio/lbry.go/extras/null"`,
 		},
 	}
 
@@ -281,7 +281,7 @@ func TestCombineTypeImports(t *testing.T) {
 		},
 		thirdParty: importList{
 			`"github.com/lbryio/sqlboiler/boil"`,
-			`"github.com/lbryio/lbry.go/null"`,
+			`"github.com/lbryio/lbry.go/extras/null"`,
 		},
 	}
 
@@ -297,7 +297,7 @@ func TestCombineImports(t *testing.T) {
 
 	a := imports{
 		standard:   importList{"fmt"},
-		thirdParty: importList{"github.com/lbryio/sqlboiler", "github.com/lbryio/lbry.go/null"},
+		thirdParty: importList{"github.com/lbryio/sqlboiler", "github.com/lbryio/lbry.go/extras/null"},
 	}
 	b := imports{
 		standard:   importList{"os"},
@@ -309,8 +309,8 @@ func TestCombineImports(t *testing.T) {
 	if c.standard[0] != "fmt" && c.standard[1] != "os" {
 		t.Errorf("Wanted: fmt, os got: %#v", c.standard)
 	}
-	if c.thirdParty[0] != "github.com/lbryio/sqlboiler" && c.thirdParty[1] != "github.com/lbryio/lbry.go/null" {
-		t.Errorf("Wanted: github.com/lbryio/sqlboiler, github.com/lbryio/lbry.go/null got: %#v", c.thirdParty)
+	if c.thirdParty[0] != "github.com/lbryio/sqlboiler" && c.thirdParty[1] != "github.com/lbryio/lbry.go/extras/null" {
+		t.Errorf("Wanted: github.com/lbryio/sqlboiler, github.com/lbryio/lbry.go/extras/null got: %#v", c.thirdParty)
 	}
 }
 
diff --git a/queries/helpers_test.go b/queries/helpers_test.go
index b6b757d..5a1802a 100644
--- a/queries/helpers_test.go
+++ b/queries/helpers_test.go
@@ -5,7 +5,7 @@ import (
 	"testing"
 	"time"
 
-	null "github.com/lbryio/lbry.go/null"
+	null "github.com/lbryio/lbry.go/extras/null"
 )
 
 type testObj struct {
diff --git a/queries/query.go b/queries/query.go
index fdd54b4..14f2d51 100644
--- a/queries/query.go
+++ b/queries/query.go
@@ -4,7 +4,7 @@ import (
 	"database/sql"
 	"fmt"
 
-	"github.com/lbryio/lbry.go/errors"
+	"github.com/lbryio/lbry.go/extras/errors"
 	"github.com/lbryio/sqlboiler/boil"
 )
 
diff --git a/randomize/randomize.go b/randomize/randomize.go
index 54c88bf..65b2a2b 100644
--- a/randomize/randomize.go
+++ b/randomize/randomize.go
@@ -14,7 +14,7 @@ import (
 	"sync/atomic"
 	"time"
 
-	null "github.com/lbryio/lbry.go/null"
+	null "github.com/lbryio/lbry.go/extras/null"
 
 	"github.com/pkg/errors"
 	"github.com/satori/go.uuid"
diff --git a/randomize/randomize_test.go b/randomize/randomize_test.go
index bc7a382..45ddf16 100644
--- a/randomize/randomize_test.go
+++ b/randomize/randomize_test.go
@@ -5,7 +5,7 @@ import (
 	"testing"
 	"time"
 
-	null "github.com/lbryio/lbry.go/null"
+	null "github.com/lbryio/lbry.go/extras/null"
 )
 
 func TestRandomizeStruct(t *testing.T) {

From eea3d349a773e4f5bcfb9a194b78674e5b92fdd5 Mon Sep 17 00:00:00 2001
From: Mark Beamer Jr <markbeamerjr@gmail.com>
Date: Mon, 3 Sep 2018 00:51:55 -0400
Subject: [PATCH 173/179] added support for 1 to 1 relations and added support
 for n unique keys for conflict resolution during merging. split out into two
 functions.

---
 templates/singleton/boil_queries.tpl | 118 +++++++++++++++++++--------
 1 file changed, 83 insertions(+), 35 deletions(-)

diff --git a/templates/singleton/boil_queries.tpl b/templates/singleton/boil_queries.tpl
index 51ed108..a881cda 100644
--- a/templates/singleton/boil_queries.tpl
+++ b/templates/singleton/boil_queries.tpl
@@ -27,11 +27,15 @@ func mergeModels(tx boil.Executor, primaryID uint64, secondaryID uint64, foreign
 	var err error
 
 	for _, conflict := range conflictingKeys {
-		err = deleteConflictsBeforeMerge(tx, conflict, primaryID, secondaryID)
-		if err != nil {
-			return err
-		}
-	}
+        if len(conflict.columns) == 1 && conflict.columns[0] == conflict.objectIdColumn {
+            err = deleteOneToOneConflictsBeforeMerge(tx, conflict, primaryID, secondaryID)
+        } else {
+            err = deleteOneToManyConflictsBeforeMerge(tx, conflict, primaryID, secondaryID)
+        }
+        if err != nil {
+            return err
+        }
+     }
 
 	for _, fk := range foreignKeys {
 		// TODO: use NewQuery here, not plain sql
@@ -48,53 +52,97 @@ func mergeModels(tx boil.Executor, primaryID uint64, secondaryID uint64, foreign
 	return checkMerge(tx, foreignKeys)
 }
 
-func deleteConflictsBeforeMerge(tx boil.Executor, conflict conflictingUniqueKey, primaryID uint64, secondaryID uint64) error {
-	conflictingColumns := strmangle.SetComplement(conflict.columns, []string{conflict.objectIdColumn})
-
-	if len(conflictingColumns) < 1 {
-		return nil
-	} else if len(conflictingColumns) > 1 {
-		return errors.Err("this doesnt work for unique keys with more than two columns (yet)")
-	}
-
+func deleteOneToOneConflictsBeforeMerge(tx boil.Executor, conflict conflictingUniqueKey, primaryID uint64, secondaryID uint64) error {
 	query := fmt.Sprintf(
-		"SELECT %s FROM %s WHERE %s IN (%s) GROUP BY %s HAVING count(distinct %s) > 1",
-		conflictingColumns[0], conflict.table, conflict.objectIdColumn,
+		"SELECT COUNT(*) FROM %s WHERE %s IN (%s)",
+		conflict.table, conflict.objectIdColumn,
 		strmangle.Placeholders(dialect.IndexPlaceholders, 2, 1, 1),
-		conflictingColumns[0], conflict.objectIdColumn,
 	)
 
-	rows, err := tx.Query(query, primaryID, secondaryID)
-	defer rows.Close()
+	var count int
+	err := tx.QueryRow(query, primaryID, secondaryID).Scan(&count)
 	if err != nil {
 		return errors.Err(err)
 	}
 
-	args := []interface{}{secondaryID}
-	for rows.Next() {
-		var value string
-		err = rows.Scan(&value)
-		if err != nil {
-			return errors.Err(err)
-		}
-		args = append(args, value)
-	}
-
-	// if no rows found, no need to delete anything
-	if len(args) < 2 {
-		return nil
+	if count > 2 {
+		return errors.Err("it should not be possible to have more than two rows here")
+	} else if count != 2 {
+		return nil // no conflicting rows
 	}
 
 	query = fmt.Sprintf(
-		"DELETE FROM %s WHERE %s = %s AND %s IN (%s)",
+		"DELETE FROM %s WHERE %s = %s",
 		conflict.table, conflict.objectIdColumn, strmangle.Placeholders(dialect.IndexPlaceholders, 1, 1, 1),
-		conflictingColumns[0], strmangle.Placeholders(dialect.IndexPlaceholders, len(args)-1, 2, 1),
 	)
 
-	_, err = tx.Exec(query, args...)
+	_, err = tx.Exec(query, secondaryID)
+	return errors.Err(err)
+}
+
+func deleteOneToManyConflictsBeforeMerge(tx boil.Executor, conflict conflictingUniqueKey, primaryID uint64, secondaryID uint64) error {
+	conflictingColumns := strmangle.SetComplement(conflict.columns, []string{conflict.objectIdColumn})
+
+	query := fmt.Sprintf(
+		"SELECT %s FROM %s WHERE %s IN (%s) GROUP BY %s HAVING count(distinct %s) > 1",
+		strings.Join(conflictingColumns, ","), conflict.table, conflict.objectIdColumn,
+		strmangle.Placeholders(dialect.IndexPlaceholders, 2, 1, 1),
+		strings.Join(conflictingColumns, ","), conflict.objectIdColumn,
+	)
+
+	//The selectParams should be the ObjectIDs to search for regarding the conflict.
+	rows, err := tx.Query(query, primaryID, secondaryID)
 	if err != nil {
 		return errors.Err(err)
 	}
+
+	//Since we don't don't know if advance how many columns the query returns, we have dynamically assign them to be
+	// used in the delete query.
+	colNames, err := rows.Columns()
+	if err != nil {
+		log.Fatal(err)
+	}
+	//Each row result of the query needs to be removed for being a conflicting row. Store each row's keys in an array.
+	var rowsToRemove = [][]interface{}(nil)
+	for rows.Next() {
+		//Set pointers for dynamic scan
+		iColPtrs := make([]interface{}, len(colNames))
+		for i := 0; i < len(colNames); i++ {
+			s := string("")
+			iColPtrs[i] = &s
+		}
+		//Dynamically scan n columns
+		err = rows.Scan(iColPtrs...)
+		if err != nil {
+			return errors.Err(err)
+		}
+		//Grab scanned values for query arguments
+		iCol := make([]interface{}, len(colNames))
+		for i, col := range iColPtrs {
+			x := col.(*string)
+			iCol[i] = *x
+		}
+		rowsToRemove = append(rowsToRemove, iCol)
+	}
+	defer rows.Close()
+
+	//This query will adjust dynamically depending on the number of conflicting keys, adding AND expressions for each
+	// key to ensure the right conflicting rows are deleted.
+	query = fmt.Sprintf(
+		"DELETE FROM %s %s",
+		conflict.table,
+		"WHERE "+strings.Join(conflict.columns, " = ? AND ")+" = ?",
+	)
+
+	//There could be multiple conflicting rows between ObjectIDs. In the SELECT query we grab each row and their column
+	// keys to be deleted here in a loop.
+	for _, rowToDelete := range rowsToRemove {
+		rowToDelete = append(rowToDelete, secondaryID)
+		_, err = tx.Exec(query, rowToDelete...)
+		if err != nil {
+			return errors.Err(err)
+		}
+	}
 	return nil
 }
 

From 29172e976b0923c864899a362c4aefe974a168d7 Mon Sep 17 00:00:00 2001
From: Mark Beamer Jr <markbeamerjr@gmail.com>
Date: Fri, 7 Sep 2018 20:51:50 -0400
Subject: [PATCH 174/179] changed from Fatal to Error - copy paste mistake.

---
 templates/singleton/boil_queries.tpl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/templates/singleton/boil_queries.tpl b/templates/singleton/boil_queries.tpl
index a881cda..3e9ebb8 100644
--- a/templates/singleton/boil_queries.tpl
+++ b/templates/singleton/boil_queries.tpl
@@ -100,7 +100,7 @@ func deleteOneToManyConflictsBeforeMerge(tx boil.Executor, conflict conflictingU
 	// used in the delete query.
 	colNames, err := rows.Columns()
 	if err != nil {
-		log.Fatal(err)
+		return errors.Err(err)
 	}
 	//Each row result of the query needs to be removed for being a conflicting row. Store each row's keys in an array.
 	var rowsToRemove = [][]interface{}(nil)

From f892107dad46b36f3487ffe336d53064c8a053d8 Mon Sep 17 00:00:00 2001
From: Mark Beamer Jr <markbeamerjr@gmail.com>
Date: Thu, 7 Feb 2019 20:24:07 -0500
Subject: [PATCH 175/179] missing import

---
 boilingcore/imports.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index b5979e3..d37c84b 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -183,6 +183,7 @@ func newImporter() importer {
 		"boil_queries": imports{
 			standard: importList{
 				`"fmt"`,
+				`"strings"`,
 			},
 			thirdParty: importList{
 				`"github.com/lbryio/lbry.go/extras/errors"`,

From 4e1b83ab3942cc6747e04065aef330b0d9dff56d Mon Sep 17 00:00:00 2001
From: Mark Beamer Jr <markbeamerjr@gmail.com>
Date: Sat, 29 Jun 2019 11:30:23 -0400
Subject: [PATCH 176/179] Add force index query mod for select query.

Fix eager loading casting for nested levels.
---
 queries/eager_load.go     | 14 ++++++++++++--
 queries/qm/query_mods.go  |  7 +++++++
 queries/query.go          |  6 ++++++
 queries/query_builders.go |  8 +++++++-
 4 files changed, 32 insertions(+), 3 deletions(-)

diff --git a/queries/eager_load.go b/queries/eager_load.go
index 081aac4..962d722 100644
--- a/queries/eager_load.go
+++ b/queries/eager_load.go
@@ -206,9 +206,16 @@ func (l loadRelationshipState) loadRelationshipsRecurse(depth int, obj reflect.V
 	}
 
 	bkind := kindStruct
-	if reflect.Indirect(loadedObject).Kind() != reflect.Struct {
+	if derefed := reflect.Indirect(loadedObject); derefed.Kind() != reflect.Struct {
 		bkind = kindPtrSliceStruct
-		loadedObject = loadedObject.Addr()
+
+		// Convert away any helper slice types
+		// elemType is *elem (from []*elem or helperSliceType)
+		// sliceType is *[]*elem
+		elemType := derefed.Type().Elem()
+		sliceType := reflect.PtrTo(reflect.SliceOf(elemType))
+
+		loadedObject = loadedObject.Addr().Convert(sliceType)
 	}
 	return l.loadRelationships(depth+1, loadedObject.Interface(), bkind)
 }
@@ -241,6 +248,9 @@ func collectLoaded(key string, loadingFrom reflect.Value) (reflect.Value, bindKi
 	if loadedType.Elem().Kind() == reflect.Struct {
 		bkind = kindStruct
 		loadedType = reflect.SliceOf(loadedType)
+	} else {
+		// Ensure that we get rid of all the helper "XSlice" types
+		loadedType = reflect.SliceOf(loadedType.Elem())
 	}
 
 	collection := reflect.MakeSlice(loadedType, 0, 0)
diff --git a/queries/qm/query_mods.go b/queries/qm/query_mods.go
index 89d31d4..6fa6e2f 100644
--- a/queries/qm/query_mods.go
+++ b/queries/qm/query_mods.go
@@ -123,6 +123,13 @@ func From(from string) QueryMod {
 	}
 }
 
+func ForceIndex( index string) QueryMod {
+	return func(q *queries.Query) {
+		queries.SetForceIndex(q, index)
+	}
+}
+
+
 // Limit the number of returned rows
 func Limit(limit int) QueryMod {
 	return func(q *queries.Query) {
diff --git a/queries/query.go b/queries/query.go
index 14f2d51..5b0ffbc 100644
--- a/queries/query.go
+++ b/queries/query.go
@@ -30,6 +30,7 @@ type Query struct {
 	selectCols []string
 	count      bool
 	from       []string
+	forceindex string
 	joins      []join
 	where      []where
 	in         []in
@@ -263,6 +264,11 @@ func SetLastWhereAsOr(q *Query) {
 	q.where[len(q.where)-1].orSeparator = true
 }
 
+// SetForceIndex sets the index to be used by the query
+func SetForceIndex(q *Query, index string){
+	q.forceindex = index
+}
+
 // SetLastInAsOr sets the or separator for the tail "IN" in the slice
 func SetLastInAsOr(q *Query) {
 	if len(q.in) == 0 {
diff --git a/queries/query_builders.go b/queries/query_builders.go
index f884f91..e682877 100644
--- a/queries/query_builders.go
+++ b/queries/query_builders.go
@@ -76,7 +76,13 @@ func buildSelectQuery(q *Query) (*bytes.Buffer, []interface{}) {
 		buf.WriteByte(')')
 	}
 
-	fmt.Fprintf(buf, " FROM %s", strings.Join(strmangle.IdentQuoteSlice(q.dialect.LQ, q.dialect.RQ, q.from), ", "))
+	if len(q.forceindex) > 0 {
+		fmt.Fprintf(buf, " FROM %s FORCE INDEX (%s)", strings.Join(strmangle.IdentQuoteSlice(q.dialect.LQ, q.dialect.RQ, q.from), ", "),q.forceindex)
+
+	}else{
+		fmt.Fprintf(buf, " FROM %s", strings.Join(strmangle.IdentQuoteSlice(q.dialect.LQ, q.dialect.RQ, q.from), ", "))
+
+	}
 
 	if len(q.joins) > 0 {
 		argsLen := len(args)

From c01b1828391ba95ef3366817aad739e264f46441 Mon Sep 17 00:00:00 2001
From: Mark Beamer Jr <markbeamerjr@gmail.com>
Date: Mon, 1 Jul 2019 23:46:37 -0400
Subject: [PATCH 177/179] Allow null query mods for dynamic queries

---
 queries/qm/query_mods.go | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/queries/qm/query_mods.go b/queries/qm/query_mods.go
index 6fa6e2f..42e881e 100644
--- a/queries/qm/query_mods.go
+++ b/queries/qm/query_mods.go
@@ -8,7 +8,9 @@ type QueryMod func(q *queries.Query)
 // Apply the query mods to the Query object
 func Apply(q *queries.Query, mods ...QueryMod) {
 	for _, mod := range mods {
-		mod(q)
+		if mod != nil {
+			mod(q)
+		}
 	}
 }
 
@@ -123,13 +125,12 @@ func From(from string) QueryMod {
 	}
 }
 
-func ForceIndex( index string) QueryMod {
+func ForceIndex(index string) QueryMod {
 	return func(q *queries.Query) {
 		queries.SetForceIndex(q, index)
 	}
 }
 
-
 // Limit the number of returned rows
 func Limit(limit int) QueryMod {
 	return func(q *queries.Query) {

From 256a6d4225b70fd17caba555c5b8f035e33db8c9 Mon Sep 17 00:00:00 2001
From: Niko Storni <niko@lbry.io>
Date: Mon, 10 Feb 2020 14:49:11 +0100
Subject: [PATCH 178/179] update lbry.go library

---
 boilingcore/imports.go      | 50 ++++++++++++++++++-------------------
 boilingcore/imports_test.go | 10 ++++----
 queries/helpers_test.go     |  2 +-
 queries/query.go            |  2 +-
 randomize/randomize.go      |  2 +-
 randomize/randomize_test.go |  2 +-
 6 files changed, 34 insertions(+), 34 deletions(-)

diff --git a/boilingcore/imports.go b/boilingcore/imports.go
index d37c84b..e20480b 100644
--- a/boilingcore/imports.go
+++ b/boilingcore/imports.go
@@ -170,8 +170,8 @@ func newImporter() importer {
 			`"time"`,
 		},
 		thirdParty: importList{
-			`"github.com/lbryio/lbry.go/extras/errors"`,
-			`"github.com/lbryio/lbry.go/extras/null"`,
+			`"github.com/lbryio/lbry.go/v2/extras/errors"`,
+			`"github.com/lbryio/lbry.go/v2/extras/null"`,
 			`"github.com/lbryio/sqlboiler/boil"`,
 			`"github.com/lbryio/sqlboiler/queries"`,
 			`"github.com/lbryio/sqlboiler/queries/qm"`,
@@ -186,7 +186,7 @@ func newImporter() importer {
 				`"strings"`,
 			},
 			thirdParty: importList{
-				`"github.com/lbryio/lbry.go/extras/errors"`,
+				`"github.com/lbryio/lbry.go/v2/extras/errors"`,
 				`"github.com/lbryio/sqlboiler/boil"`,
 				`"github.com/lbryio/sqlboiler/queries"`,
 				`"github.com/lbryio/sqlboiler/queries/qm"`,
@@ -195,7 +195,7 @@ func newImporter() importer {
 		},
 		"boil_types": {
 			thirdParty: importList{
-				`"github.com/lbryio/lbry.go/extras/errors"`,
+				`"github.com/lbryio/lbry.go/v2/extras/errors"`,
 				`"github.com/lbryio/sqlboiler/strmangle"`,
 			},
 		},
@@ -228,7 +228,7 @@ func newImporter() importer {
 			},
 			thirdParty: importList{
 				`"github.com/kat-co/vala"`,
-				`"github.com/lbryio/lbry.go/extras/errors"`,
+				`"github.com/lbryio/lbry.go/v2/extras/errors"`,
 				`"github.com/lbryio/sqlboiler/boil"`,
 				`"github.com/spf13/viper"`,
 			},
@@ -266,7 +266,7 @@ func newImporter() importer {
 				`"strings"`,
 			},
 			thirdParty: importList{
-				`"github.com/lbryio/lbry.go/extras/errors"`,
+				`"github.com/lbryio/lbry.go/v2/extras/errors"`,
 				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
 				`"github.com/lbryio/sqlboiler/randomize"`,
 				`_ "github.com/lib/pq"`,
@@ -286,7 +286,7 @@ func newImporter() importer {
 			},
 			thirdParty: importList{
 				`_ "github.com/go-sql-driver/mysql"`,
-				`"github.com/lbryio/lbry.go/extras/errors"`,
+				`"github.com/lbryio/lbry.go/v2/extras/errors"`,
 				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
 				`"github.com/lbryio/sqlboiler/randomize"`,
 				`"github.com/spf13/viper"`,
@@ -303,7 +303,7 @@ func newImporter() importer {
 			},
 			thirdParty: importList{
 				`_ "github.com/denisenkom/go-mssqldb"`,
-				`"github.com/lbryio/lbry.go/extras/errors"`,
+				`"github.com/lbryio/lbry.go/v2/extras/errors"`,
 				`"github.com/lbryio/sqlboiler/bdb/drivers"`,
 				`"github.com/lbryio/sqlboiler/randomize"`,
 				`"github.com/spf13/viper"`,
@@ -316,55 +316,55 @@ func newImporter() importer {
 	// TranslateColumnType to see the type assignments.
 	imp.BasedOnType = mapImports{
 		"null.Float32": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Float64": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Int": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Int8": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Int16": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Int32": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Int64": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Uint": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Uint8": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Uint16": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Uint32": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Uint64": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.String": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Bool": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Time": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.JSON": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"null.Bytes": {
-			thirdParty: importList{`"github.com/lbryio/lbry.go/extras/null"`},
+			thirdParty: importList{`"github.com/lbryio/lbry.go/v2/extras/null"`},
 		},
 		"time.Time": {
 			standard: importList{`"time"`},
diff --git a/boilingcore/imports_test.go b/boilingcore/imports_test.go
index 6d22956..d0043c0 100644
--- a/boilingcore/imports_test.go
+++ b/boilingcore/imports_test.go
@@ -246,7 +246,7 @@ func TestCombineTypeImports(t *testing.T) {
 		},
 		thirdParty: importList{
 			`"github.com/lbryio/sqlboiler/boil"`,
-			`"github.com/lbryio/lbry.go/extras/null"`,
+			`"github.com/lbryio/lbry.go/v2/extras/null"`,
 		},
 	}
 
@@ -281,7 +281,7 @@ func TestCombineTypeImports(t *testing.T) {
 		},
 		thirdParty: importList{
 			`"github.com/lbryio/sqlboiler/boil"`,
-			`"github.com/lbryio/lbry.go/extras/null"`,
+			`"github.com/lbryio/lbry.go/v2/extras/null"`,
 		},
 	}
 
@@ -297,7 +297,7 @@ func TestCombineImports(t *testing.T) {
 
 	a := imports{
 		standard:   importList{"fmt"},
-		thirdParty: importList{"github.com/lbryio/sqlboiler", "github.com/lbryio/lbry.go/extras/null"},
+		thirdParty: importList{"github.com/lbryio/sqlboiler", "github.com/lbryio/lbry.go/v2/extras/null"},
 	}
 	b := imports{
 		standard:   importList{"os"},
@@ -309,8 +309,8 @@ func TestCombineImports(t *testing.T) {
 	if c.standard[0] != "fmt" && c.standard[1] != "os" {
 		t.Errorf("Wanted: fmt, os got: %#v", c.standard)
 	}
-	if c.thirdParty[0] != "github.com/lbryio/sqlboiler" && c.thirdParty[1] != "github.com/lbryio/lbry.go/extras/null" {
-		t.Errorf("Wanted: github.com/lbryio/sqlboiler, github.com/lbryio/lbry.go/extras/null got: %#v", c.thirdParty)
+	if c.thirdParty[0] != "github.com/lbryio/sqlboiler" && c.thirdParty[1] != "github.com/lbryio/lbry.go/v2/extras/null" {
+		t.Errorf("Wanted: github.com/lbryio/sqlboiler, github.com/lbryio/lbry.go/v2/extras/null got: %#v", c.thirdParty)
 	}
 }
 
diff --git a/queries/helpers_test.go b/queries/helpers_test.go
index 5a1802a..fd093e3 100644
--- a/queries/helpers_test.go
+++ b/queries/helpers_test.go
@@ -5,7 +5,7 @@ import (
 	"testing"
 	"time"
 
-	null "github.com/lbryio/lbry.go/extras/null"
+	null "github.com/lbryio/lbry.go/v2/extras/null"
 )
 
 type testObj struct {
diff --git a/queries/query.go b/queries/query.go
index 5b0ffbc..e3a6470 100644
--- a/queries/query.go
+++ b/queries/query.go
@@ -4,7 +4,7 @@ import (
 	"database/sql"
 	"fmt"
 
-	"github.com/lbryio/lbry.go/extras/errors"
+	"github.com/lbryio/lbry.go/v2/extras/errors"
 	"github.com/lbryio/sqlboiler/boil"
 )
 
diff --git a/randomize/randomize.go b/randomize/randomize.go
index 65b2a2b..30592bf 100644
--- a/randomize/randomize.go
+++ b/randomize/randomize.go
@@ -14,7 +14,7 @@ import (
 	"sync/atomic"
 	"time"
 
-	null "github.com/lbryio/lbry.go/extras/null"
+	null "github.com/lbryio/lbry.go/v2/extras/null"
 
 	"github.com/pkg/errors"
 	"github.com/satori/go.uuid"
diff --git a/randomize/randomize_test.go b/randomize/randomize_test.go
index 45ddf16..71afb55 100644
--- a/randomize/randomize_test.go
+++ b/randomize/randomize_test.go
@@ -5,7 +5,7 @@ import (
 	"testing"
 	"time"
 
-	null "github.com/lbryio/lbry.go/extras/null"
+	null "github.com/lbryio/lbry.go/v2/extras/null"
 )
 
 func TestRandomizeStruct(t *testing.T) {

From 3db4f30f564e65e40f5467f76692501c21489a46 Mon Sep 17 00:00:00 2001
From: Mark Beamer Jr <markbeamerjr@gmail.com>
Date: Wed, 19 Aug 2020 23:43:39 -0400
Subject: [PATCH 179/179] Fix multi-depth eager loading of relationships. If a
 relationship is nil, do not add it to the collection for checking the next
 depth level.

---
 queries/eager_load.go | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/queries/eager_load.go b/queries/eager_load.go
index 962d722..8992290 100644
--- a/queries/eager_load.go
+++ b/queries/eager_load.go
@@ -5,9 +5,9 @@ import (
 	"reflect"
 	"strings"
 
-	"github.com/pkg/errors"
 	"github.com/lbryio/sqlboiler/boil"
 	"github.com/lbryio/sqlboiler/strmangle"
+	"github.com/pkg/errors"
 )
 
 type loadRelationshipState struct {
@@ -259,9 +259,13 @@ func collectLoaded(key string, loadingFrom reflect.Value) (reflect.Value, bindKi
 	for {
 		switch bkind {
 		case kindStruct:
-			collection = reflect.Append(collection, loadedObject)
+			if !loadedObject.IsNil() {
+				collection = reflect.Append(collection, loadedObject)
+			}
 		case kindPtrSliceStruct:
-			collection = reflect.AppendSlice(collection, loadedObject)
+			if !loadedObject.IsNil() {
+				collection = reflect.AppendSlice(collection, loadedObject)
+			}
 		}
 
 		i++