Merge branch 'dev'

This commit is contained in:
Aaron L 2016-09-20 21:56:54 -07:00
commit 0cf3939ed0
58 changed files with 2032 additions and 1157 deletions

View file

@ -185,6 +185,10 @@ fmt.Println(len(users.R.FavoriteMovies))
a *composite primary key* that encompasses both foreign table foreign keys. For example, on a a *composite primary key* that encompasses both foreign table foreign keys. For example, on a
join table named `user_videos` you should have: `primary key(user_id, video_id)`, with both `user_id` join table named `user_videos` you should have: `primary key(user_id, video_id)`, with both `user_id`
and `video_id` being foreign key columns to the users and videos tables respectively. and `video_id` being foreign key columns to the users and videos tables respectively.
* For MySQL if using the `github.com/go-sql-driver/mysql` driver, please activate
[time.Time parsing](https://github.com/go-sql-driver/mysql#timetime-support) when making your
MySQL database connection. SQLBoiler uses `time.Time` and `null.Time` to represent time in
it's models and without this enabled any models with `DATE`/`DATETIME` columns will not work.
### Pro Tips ### Pro Tips
* Foreign key column names should end with `_id`. * Foreign key column names should end with `_id`.
@ -1036,10 +1040,10 @@ you will need to call the `Reload` methods on those yourself.
jet, err := models.FindJet(db, 1) jet, err := models.FindJet(db, 1)
// Check if the pilot assigned to this jet exists. // Check if the pilot assigned to this jet exists.
exists := jet.Pilot(db).Exists() exists, err := jet.Pilot(db).Exists()
// Check if the pilot with ID 5 exists // Check if the pilot with ID 5 exists
exists := models.Pilots(db, Where("id=?", 5)).Exists() exists, err := models.Pilots(db, Where("id=?", 5)).Exists()
``` ```
## FAQ ## FAQ
@ -1074,6 +1078,10 @@ with all Postgres drivers. Example:
Please note that multi-dimensional Postgres ARRAY types are not supported at this time. Please note that multi-dimensional Postgres ARRAY types are not supported at this time.
#### Why aren't my time.Time or null.Time fields working in MySQL?
You *must* use a DSN flag in MySQL connections, see: [Requirements](#requirements)
#### Where is the homepage? #### Where is the homepage?
The homepage for the [SQLBoiler](https://github.com/vattle/sqlboiler) [Golang ORM](https://github.com/vattle/sqlboiler) The homepage for the [SQLBoiler](https://github.com/vattle/sqlboiler) [Golang ORM](https://github.com/vattle/sqlboiler)

View file

@ -5,11 +5,6 @@ import "github.com/vattle/sqlboiler/strmangle"
// Column holds information about a database column. // Column holds information about a database column.
// Types are Go types, converted by TranslateColumnType. // Types are Go types, converted by TranslateColumnType.
type Column struct { type Column struct {
// ArrType is the underlying data type of the Postgres
// ARRAY type. See here:
// https://www.postgresql.org/docs/9.1/static/infoschema-element-types.html
ArrType *string
UDTName string
Name string Name string
Type string Type string
DBType string DBType string
@ -17,6 +12,13 @@ type Column struct {
Nullable bool Nullable bool
Unique bool Unique bool
Validated bool Validated bool
// Postgres only extension bits
// ArrType is the underlying data type of the Postgres
// ARRAY type. See here:
// https://www.postgresql.org/docs/9.1/static/infoschema-element-types.html
ArrType *string
UDTName string
} }
// ColumnNames of the columns. // ColumnNames of the columns.

View file

@ -47,6 +47,10 @@ func MySQLBuildQueryString(user, pass, dbname, host string, port int, sslmode st
config.Addr += ":" + strconv.Itoa(port) config.Addr += ":" + strconv.Itoa(port)
config.TLSConfig = sslmode config.TLSConfig = sslmode
// 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.
config.ParseTime = true
return config.FormatDSN() return config.FormatDSN()
} }
@ -256,7 +260,9 @@ func (m *MySQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
c.Type = "null.Int8" c.Type = "null.Int8"
case "smallint": case "smallint":
c.Type = "null.Int16" c.Type = "null.Int16"
case "mediumint", "int", "integer": case "mediumint":
c.Type = "null.Int32"
case "int", "integer":
c.Type = "null.Int" c.Type = "null.Int"
case "bigint": case "bigint":
c.Type = "null.Int64" c.Type = "null.Int64"
@ -281,10 +287,12 @@ func (m *MySQLDriver) TranslateColumnType(c bdb.Column) bdb.Column {
c.Type = "int8" c.Type = "int8"
case "smallint": case "smallint":
c.Type = "int16" c.Type = "int16"
case "mediumint", "int", "integer": case "mediumint":
c.Type = "int32"
case "int", "integer":
c.Type = "int" c.Type = "int"
case "bigint": case "bigint":
c.Type = "null.Int64" c.Type = "int64"
case "float": case "float":
c.Type = "float32" c.Type = "float32"
case "double", "double precision", "real": case "double", "double precision", "real":

View file

@ -119,5 +119,6 @@ func setForeignKeyConstraints(t *Table, tables []Table) {
} }
func setRelationships(t *Table, tables []Table) { func setRelationships(t *Table, tables []Table) {
t.ToOneRelationships = toOneRelationships(*t, tables)
t.ToManyRelationships = toManyRelationships(*t, tables) t.ToManyRelationships = toManyRelationships(*t, tables)
} }

View file

@ -127,13 +127,13 @@ func TestTables(t *testing.T) {
if len(pilots.Columns) != 2 { if len(pilots.Columns) != 2 {
t.Error() t.Error()
} }
if pilots.ToManyRelationships[0].ForeignTable != "jets" { if pilots.ToOneRelationships[0].ForeignTable != "jets" {
t.Error("want a to many to jets") t.Error("want a to many to jets")
} }
if pilots.ToManyRelationships[1].ForeignTable != "licenses" { if pilots.ToManyRelationships[0].ForeignTable != "licenses" {
t.Error("want a to many to languages") t.Error("want a to many to languages")
} }
if pilots.ToManyRelationships[2].ForeignTable != "languages" { if pilots.ToManyRelationships[1].ForeignTable != "languages" {
t.Error("want a to many to languages") t.Error("want a to many to languages")
} }

View file

@ -1,5 +1,21 @@
package bdb package bdb
// ToOneRelationship describes a relationship between two tables where the local
// table has no id, and the foregin table has an id that matches a column in the
// local table, that column is also unique which changes the dynamic into a
// one-to-one style, not a to-many.
type ToOneRelationship struct {
Table string
Column string
Nullable bool
Unique bool
ForeignTable string
ForeignColumn string
ForeignColumnNullable bool
ForeignColumnUnique bool
}
// ToManyRelationship describes a relationship between two tables where the // ToManyRelationship describes a relationship between two tables where the
// local table has no id, and the foreign table has an id that matches a column // local table has no id, and the foreign table has an id that matches a column
// in the local table. // in the local table.
@ -26,31 +42,64 @@ type ToManyRelationship struct {
JoinForeignColumnUnique bool JoinForeignColumnUnique bool
} }
// ToOneRelationships relationship lookups
// Input should be the sql name of a table like: videos
func ToOneRelationships(table string, tables []Table) []ToOneRelationship {
localTable := GetTable(tables, table)
return toOneRelationships(localTable, tables)
}
// ToManyRelationships relationship lookups // ToManyRelationships relationship lookups
// Input should be the sql name of a table like: videos // Input should be the sql name of a table like: videos
func ToManyRelationships(table string, tables []Table) []ToManyRelationship { func ToManyRelationships(table string, tables []Table) []ToManyRelationship {
localTable := GetTable(tables, table) localTable := GetTable(tables, table)
return toManyRelationships(localTable, tables) return toManyRelationships(localTable, tables)
} }
func toOneRelationships(table Table, tables []Table) []ToOneRelationship {
var relationships []ToOneRelationship
for _, t := range tables {
for _, f := range t.FKeys {
if f.ForeignTable == table.Name && !t.IsJoinTable && f.Unique {
relationships = append(relationships, buildToOneRelationship(table, f, t, tables))
}
}
}
return relationships
}
func toManyRelationships(table Table, tables []Table) []ToManyRelationship { func toManyRelationships(table Table, tables []Table) []ToManyRelationship {
var relationships []ToManyRelationship var relationships []ToManyRelationship
for _, t := range tables { for _, t := range tables {
for _, f := range t.FKeys { for _, f := range t.FKeys {
if f.ForeignTable != table.Name { if f.ForeignTable == table.Name && !f.Unique {
continue relationships = append(relationships, buildToManyRelationship(table, f, t, tables))
} }
relationships = append(relationships, buildRelationship(table, f, t, tables))
} }
} }
return relationships return relationships
} }
func buildRelationship(localTable Table, foreignKey ForeignKey, foreignTable Table, tables []Table) ToManyRelationship { func buildToOneRelationship(localTable Table, foreignKey ForeignKey, foreignTable Table, tables []Table) ToOneRelationship {
return ToOneRelationship{
Table: localTable.Name,
Column: foreignKey.ForeignColumn,
Nullable: foreignKey.ForeignColumnNullable,
Unique: foreignKey.ForeignColumnUnique,
ForeignTable: foreignTable.Name,
ForeignColumn: foreignKey.Column,
ForeignColumnNullable: foreignKey.Nullable,
ForeignColumnUnique: foreignKey.Unique,
}
}
func buildToManyRelationship(localTable Table, foreignKey ForeignKey, foreignTable Table, tables []Table) ToManyRelationship {
if !foreignTable.IsJoinTable { if !foreignTable.IsJoinTable {
col := localTable.GetColumn(foreignKey.ForeignColumn) col := localTable.GetColumn(foreignKey.ForeignColumn)
return ToManyRelationship{ return ToManyRelationship{

View file

@ -5,67 +5,128 @@ import (
"testing" "testing"
) )
func TestToOneRelationships(t *testing.T) {
t.Parallel()
tables := []Table{
{
Name: "pilots",
Columns: []Column{{Name: "id", Unique: true}, {Name: "name", Unique: true}}},
{
Name: "airports",
Columns: []Column{{Name: "id", Unique: true}, {Name: "size", Unique: true}},
},
{
Name: "jets",
Columns: []Column{{Name: "id", Unique: true}, {Name: "pilot_id", Unique: true}, {Name: "airport_id", Unique: true}},
FKeys: []ForeignKey{
{Name: "jets_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Unique: true},
{Name: "jets_airport_id_fk", Column: "airport_id", ForeignTable: "airports", ForeignColumn: "id", Unique: true},
},
},
{
Name: "licenses",
Columns: []Column{{Name: "id", Unique: true}, {Name: "pilot_id", Unique: true}},
FKeys: []ForeignKey{
{Name: "licenses_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Unique: true},
},
},
{
Name: "hangars",
Columns: []Column{{Name: "id", Unique: true}, {Name: "name", Unique: true}},
},
{
Name: "languages",
Columns: []Column{{Name: "id", Unique: true}, {Name: "language", Unique: true}},
},
{
Name: "pilot_languages",
IsJoinTable: true,
Columns: []Column{{Name: "pilot_id", Unique: true}, {Name: "language_id", Unique: true}},
FKeys: []ForeignKey{
{Name: "pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Unique: true},
{Name: "language_id_fk", Column: "language_id", ForeignTable: "languages", ForeignColumn: "id", Unique: true},
},
},
}
relationships := ToOneRelationships("pilots", tables)
expected := []ToOneRelationship{
{
Table: "pilots",
Column: "id",
Nullable: false,
Unique: false,
ForeignTable: "jets",
ForeignColumn: "pilot_id",
ForeignColumnNullable: false,
ForeignColumnUnique: true,
},
{
Table: "pilots",
Column: "id",
Nullable: false,
Unique: false,
ForeignTable: "licenses",
ForeignColumn: "pilot_id",
ForeignColumnNullable: false,
ForeignColumnUnique: true,
},
}
if len(relationships) != 2 {
t.Error("wrong # of relationships", len(relationships))
}
for i, v := range relationships {
if !reflect.DeepEqual(v, expected[i]) {
t.Errorf("[%d] Mismatch between relationships:\n\nwant:%#v\n\ngot:%#v\n\n", i, expected[i], v)
}
}
}
func TestToManyRelationships(t *testing.T) { func TestToManyRelationships(t *testing.T) {
t.Parallel() t.Parallel()
tables := []Table{ tables := []Table{
{ {
Name: "pilots", Name: "pilots",
Columns: []Column{ Columns: []Column{{Name: "id"}, {Name: "name"}},
{Name: "id"},
{Name: "name"},
},
}, },
{ {
Name: "airports", Name: "airports",
Columns: []Column{ Columns: []Column{{Name: "id"}, {Name: "size"}},
{Name: "id"},
{Name: "size"},
},
}, },
{ {
Name: "jets", Name: "jets",
Columns: []Column{ Columns: []Column{{Name: "id"}, {Name: "pilot_id"}, {Name: "airport_id"}},
{Name: "id"},
{Name: "pilot_id"},
{Name: "airport_id"},
},
FKeys: []ForeignKey{ FKeys: []ForeignKey{
{Name: "jets_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id"}, {Name: "jets_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id"},
{Name: "jets_airport_id_fk", Column: "airport_id", ForeignTable: "airports", ForeignColumn: "id"}, {Name: "jets_airport_id_fk", Column: "airport_id", ForeignTable: "airports", ForeignColumn: "id"},
}, },
}, },
{ {
Name: "licenses", Name: "licenses",
Columns: []Column{ Columns: []Column{{Name: "id"}, {Name: "pilot_id"}},
{Name: "id"},
{Name: "pilot_id"},
},
FKeys: []ForeignKey{ FKeys: []ForeignKey{
{Name: "licenses_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id"}, {Name: "licenses_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id"},
}, },
}, },
{ {
Name: "hangars", Name: "hangars",
Columns: []Column{ Columns: []Column{{Name: "id"}, {Name: "name"}},
{Name: "id"},
{Name: "name"},
},
}, },
{ {
Name: "languages", Name: "languages",
Columns: []Column{ Columns: []Column{{Name: "id"}, {Name: "language"}},
{Name: "id"},
{Name: "language"},
},
}, },
{ {
Name: "pilot_languages", Name: "pilot_languages",
IsJoinTable: true, IsJoinTable: true,
Columns: []Column{ Columns: []Column{{Name: "pilot_id"}, {Name: "language_id"}},
{Name: "pilot_id"},
{Name: "language_id"},
},
FKeys: []ForeignKey{ FKeys: []ForeignKey{
{Name: "pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id"}, {Name: "pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id"},
{Name: "language_id_fk", Column: "language_id", ForeignTable: "languages", ForeignColumn: "id"}, {Name: "language_id_fk", Column: "language_id", ForeignTable: "languages", ForeignColumn: "id"},
@ -132,7 +193,7 @@ func TestToManyRelationships(t *testing.T) {
for i, v := range relationships { for i, v := range relationships {
if !reflect.DeepEqual(v, expected[i]) { if !reflect.DeepEqual(v, expected[i]) {
t.Errorf("[%d] Mismatch between relationships:\n\n%#v\n\n%#v\n\n", i, v, expected[i]) t.Errorf("[%d] Mismatch between relationships:\n\nwant:%#v\n\ngot:%#v\n\n", i, expected[i], v)
} }
} }
} }
@ -142,65 +203,42 @@ func TestToManyRelationshipsNull(t *testing.T) {
tables := []Table{ tables := []Table{
{ {
Name: "pilots", Name: "pilots",
Columns: []Column{ Columns: []Column{{Name: "id", Nullable: true}, {Name: "name", Nullable: true}}},
{Name: "id", Nullable: true, Unique: true}, {
{Name: "name", Nullable: true, Unique: true}, Name: "airports",
}, Columns: []Column{{Name: "id", Nullable: true}, {Name: "size", Nullable: true}},
}, },
{ {
Name: "airports", Name: "jets",
Columns: []Column{ Columns: []Column{{Name: "id", Nullable: true}, {Name: "pilot_id", Nullable: true}, {Name: "airport_id", Nullable: true}},
{Name: "id", Nullable: true, Unique: true},
{Name: "size", Nullable: true, Unique: true},
},
},
{
Name: "jets",
Columns: []Column{
{Name: "id", Nullable: true, Unique: true},
{Name: "pilot_id", Nullable: true, Unique: true},
{Name: "airport_id", Nullable: true, Unique: true},
},
FKeys: []ForeignKey{ FKeys: []ForeignKey{
{Name: "jets_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Nullable: true, Unique: true}, {Name: "jets_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Nullable: true},
{Name: "jets_airport_id_fk", Column: "airport_id", ForeignTable: "airports", ForeignColumn: "id", Nullable: true, Unique: true}, {Name: "jets_airport_id_fk", Column: "airport_id", ForeignTable: "airports", ForeignColumn: "id", Nullable: true},
}, },
}, },
{ {
Name: "licenses", Name: "licenses",
Columns: []Column{ Columns: []Column{{Name: "id", Nullable: true}, {Name: "pilot_id", Nullable: true}},
{Name: "id", Nullable: true, Unique: true},
{Name: "pilot_id", Nullable: true, Unique: true},
},
FKeys: []ForeignKey{ FKeys: []ForeignKey{
{Name: "licenses_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Nullable: true, Unique: true}, {Name: "licenses_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Nullable: true},
}, },
}, },
{ {
Name: "hangars", Name: "hangars",
Columns: []Column{ Columns: []Column{{Name: "id", Nullable: true}, {Name: "name", Nullable: true}},
{Name: "id", Nullable: true, Unique: true},
{Name: "name", Nullable: true, Unique: true},
},
}, },
{ {
Name: "languages", Name: "languages",
Columns: []Column{ Columns: []Column{{Name: "id", Nullable: true}, {Name: "language", Nullable: true}},
{Name: "id", Nullable: true, Unique: true},
{Name: "language", Nullable: true, Unique: true},
},
}, },
{ {
Name: "pilot_languages", Name: "pilot_languages",
IsJoinTable: true, IsJoinTable: true,
Columns: []Column{ Columns: []Column{{Name: "pilot_id", Nullable: true}, {Name: "language_id", Nullable: true}},
{Name: "pilot_id", Nullable: true, Unique: true},
{Name: "language_id", Nullable: true, Unique: true},
},
FKeys: []ForeignKey{ FKeys: []ForeignKey{
{Name: "pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Nullable: true, Unique: true}, {Name: "pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Nullable: true},
{Name: "language_id_fk", Column: "language_id", ForeignTable: "languages", ForeignColumn: "id", Nullable: true, Unique: true}, {Name: "language_id_fk", Column: "language_id", ForeignTable: "languages", ForeignColumn: "id", Nullable: true},
}, },
}, },
} }
@ -215,12 +253,12 @@ func TestToManyRelationshipsNull(t *testing.T) {
Table: "pilots", Table: "pilots",
Column: "id", Column: "id",
Nullable: true, Nullable: true,
Unique: true, Unique: false,
ForeignTable: "jets", ForeignTable: "jets",
ForeignColumn: "pilot_id", ForeignColumn: "pilot_id",
ForeignColumnNullable: true, ForeignColumnNullable: true,
ForeignColumnUnique: true, ForeignColumnUnique: false,
ToJoinTable: false, ToJoinTable: false,
}, },
@ -228,12 +266,12 @@ func TestToManyRelationshipsNull(t *testing.T) {
Table: "pilots", Table: "pilots",
Column: "id", Column: "id",
Nullable: true, Nullable: true,
Unique: true, Unique: false,
ForeignTable: "licenses", ForeignTable: "licenses",
ForeignColumn: "pilot_id", ForeignColumn: "pilot_id",
ForeignColumnNullable: true, ForeignColumnNullable: true,
ForeignColumnUnique: true, ForeignColumnUnique: false,
ToJoinTable: false, ToJoinTable: false,
}, },
@ -241,29 +279,29 @@ func TestToManyRelationshipsNull(t *testing.T) {
Table: "pilots", Table: "pilots",
Column: "id", Column: "id",
Nullable: true, Nullable: true,
Unique: true, Unique: false,
ForeignTable: "languages", ForeignTable: "languages",
ForeignColumn: "id", ForeignColumn: "id",
ForeignColumnNullable: true, ForeignColumnNullable: true,
ForeignColumnUnique: true, ForeignColumnUnique: false,
ToJoinTable: true, ToJoinTable: true,
JoinTable: "pilot_languages", JoinTable: "pilot_languages",
JoinLocalColumn: "pilot_id", JoinLocalColumn: "pilot_id",
JoinLocalColumnNullable: true, JoinLocalColumnNullable: true,
JoinLocalColumnUnique: true, JoinLocalColumnUnique: false,
JoinForeignColumn: "language_id", JoinForeignColumn: "language_id",
JoinForeignColumnNullable: true, JoinForeignColumnNullable: true,
JoinForeignColumnUnique: true, JoinForeignColumnUnique: false,
}, },
} }
for i, v := range relationships { for i, v := range relationships {
if !reflect.DeepEqual(v, expected[i]) { if !reflect.DeepEqual(v, expected[i]) {
t.Errorf("[%d] Mismatch between relationships null:\n\n%#v\n\n%#v\n\n", i, v, expected[i]) t.Errorf("[%d] Mismatch between relationships:\n\nwant:%#v\n\ngot:%#v\n\n", i, expected[i], v)
} }
} }
} }

View file

@ -15,6 +15,7 @@ type Table struct {
IsJoinTable bool IsJoinTable bool
ToOneRelationships []ToOneRelationship
ToManyRelationships []ToManyRelationship ToManyRelationships []ToManyRelationship
} }

View file

@ -3,10 +3,13 @@ test:
- mkdir -p /home/ubuntu/.go_workspace/src/github.com/jstemmer - mkdir -p /home/ubuntu/.go_workspace/src/github.com/jstemmer
- git clone git@github.com:nullbio/go-junit-report.git /home/ubuntu/.go_workspace/src/github.com/jstemmer/go-junit-report - git clone git@github.com:nullbio/go-junit-report.git /home/ubuntu/.go_workspace/src/github.com/jstemmer/go-junit-report
- go install github.com/jstemmer/go-junit-report - go install github.com/jstemmer/go-junit-report
- echo -e "[postgres]\nhost=\"localhost\"\nport=5432\nuser=\"ubuntu\"\ndbname=\"sqlboiler\"" > sqlboiler.toml - 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 - createdb -U ubuntu sqlboiler
- psql -U ubuntu sqlboiler < ./testdata/test_schema.sql - psql -U ubuntu sqlboiler < ./testdata/postgres_test_schema.sql
- ./sqlboiler postgres - 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: override:
- go test -v -race ./... > $CIRCLE_ARTIFACTS/gotest.txt - go test -v -race ./... > $CIRCLE_ARTIFACTS/gotest.txt
post: post:

View file

@ -143,10 +143,11 @@ func removeDuplicates(dedup []string) []string {
var defaultTemplateImports = imports{ var defaultTemplateImports = imports{
standard: importList{ standard: importList{
`"fmt"`, `"bytes"`,
`"strings"`,
`"database/sql"`, `"database/sql"`,
`"fmt"`,
`"reflect"`, `"reflect"`,
`"strings"`,
`"sync"`, `"sync"`,
`"time"`, `"time"`,
}, },
@ -177,8 +178,9 @@ var defaultSingletonTemplateImports = map[string]imports{
var defaultTestTemplateImports = imports{ var defaultTestTemplateImports = imports{
standard: importList{ standard: importList{
`"testing"`, `"bytes"`,
`"reflect"`, `"reflect"`,
`"testing"`,
}, },
thirdParty: importList{ thirdParty: importList{
`"github.com/vattle/sqlboiler/boil"`, `"github.com/vattle/sqlboiler/boil"`,

View file

@ -119,7 +119,7 @@ func buildDeleteQuery(q *Query) (*bytes.Buffer, []interface{}) {
where, whereArgs := whereClause(q, 1) where, whereArgs := whereClause(q, 1)
if len(whereArgs) != 0 { if len(whereArgs) != 0 {
args = append(args, whereArgs) args = append(args, whereArgs...)
} }
buf.WriteString(where) buf.WriteString(where)
@ -190,6 +190,17 @@ func BuildUpsertQueryMySQL(dia Dialect, tableName string, update, whitelist []st
buf := strmangle.GetBuffer() buf := strmangle.GetBuffer()
defer strmangle.PutBuffer(buf) defer strmangle.PutBuffer(buf)
if len(update) == 0 {
fmt.Fprintf(
buf,
"INSERT IGNORE INTO %s (%s) VALUES (%s)",
tableName,
strings.Join(whitelist, ", "),
strmangle.Placeholders(dia.IndexPlaceholders, len(whitelist), 1, 1),
)
return buf.String()
}
fmt.Fprintf( fmt.Fprintf(
buf, buf,
"INSERT INTO %s (%s) VALUES (%s) ON DUPLICATE KEY UPDATE ", "INSERT INTO %s (%s) VALUES (%s) ON DUPLICATE KEY UPDATE ",

View file

@ -63,19 +63,19 @@ func TestBuildQuery(t *testing.T) {
delete: true, delete: true,
from: []string{"thing happy", `upset as "sad"`, "fun", "thing as stuff", `"angry" as mad`}, from: []string{"thing happy", `upset as "sad"`, "fun", "thing as stuff", `"angry" as mad`},
where: []where{ where: []where{
{clause: "a=?", args: []interface{}{}}, {clause: "a=?", args: []interface{}{1}},
{clause: "b=?", args: []interface{}{}}, {clause: "b=?", args: []interface{}{2}},
{clause: "c=?", args: []interface{}{}}, {clause: "c=?", args: []interface{}{3}},
}, },
}, nil}, }, []interface{}{1, 2, 3}},
{&Query{ {&Query{
delete: true, delete: true,
from: []string{"thing happy", `upset as "sad"`, "fun", "thing as stuff", `"angry" as mad`}, from: []string{"thing happy", `upset as "sad"`, "fun", "thing as stuff", `"angry" as mad`},
where: []where{ where: []where{
{clause: "(id=? and thing=?) or stuff=?", args: []interface{}{}}, {clause: "(id=? and thing=?) or stuff=?", args: []interface{}{1, 2, 3}},
}, },
limit: 5, limit: 5,
}, nil}, }, []interface{}{1, 2, 3}},
{&Query{ {&Query{
from: []string{"thing happy", `"fun"`, `stuff`}, from: []string{"thing happy", `"fun"`, `stuff`},
update: map[string]interface{}{ update: map[string]interface{}{

View file

@ -49,7 +49,7 @@ var (
rgxValidTime = regexp.MustCompile(`[2-9]+`) rgxValidTime = regexp.MustCompile(`[2-9]+`)
validatedTypes = []string{ validatedTypes = []string{
"inet", "line", "uuid", "interval", "inet", "line", "uuid", "interval", "mediumint",
"json", "jsonb", "box", "cidr", "circle", "json", "jsonb", "box", "cidr", "circle",
"lseg", "macaddr", "path", "pg_lsn", "point", "lseg", "macaddr", "path", "pg_lsn", "point",
"polygon", "txid_snapshot", "money", "hstore", "polygon", "txid_snapshot", "money", "hstore",
@ -135,7 +135,7 @@ func Struct(s *Seed, str interface{}, colTypes map[string]string, canBeNull bool
// not cause mismatches in the test data comparisons. // not cause mismatches in the test data comparisons.
func randDate(s *Seed) time.Time { func randDate(s *Seed) time.Time {
t := time.Date( t := time.Date(
1850+s.nextInt()%160, 1972+s.nextInt()%60,
time.Month(1+(s.nextInt()%12)), time.Month(1+(s.nextInt()%12)),
1+(s.nextInt()%25), 1+(s.nextInt()%25),
0, 0,
@ -221,6 +221,13 @@ func randomizeField(s *Seed, field reflect.Value, fieldType string, canBeNull bo
field.Set(reflect.ValueOf(value)) field.Set(reflect.ValueOf(value))
return nil return nil
} }
case typeNullInt32:
if fieldType == "mediumint" {
// 8388607 is the max for 3 byte int
value = null.NewInt32(int32(s.nextInt())%8388607, true)
field.Set(reflect.ValueOf(value))
return nil
}
case typeNullJSON: case typeNullJSON:
value = null.NewJSON([]byte(fmt.Sprintf(`"%s"`, randStr(s, 1))), true) value = null.NewJSON([]byte(fmt.Sprintf(`"%s"`, randStr(s, 1))), true)
field.Set(reflect.ValueOf(value)) field.Set(reflect.ValueOf(value))
@ -287,6 +294,13 @@ func randomizeField(s *Seed, field reflect.Value, fieldType string, canBeNull bo
field.Set(reflect.ValueOf(value)) field.Set(reflect.ValueOf(value))
return nil return nil
} }
case reflect.Int32:
if fieldType == "mediumint" {
// 8388607 is the max for 3 byte int
value = int32(s.nextInt()) % 8388607
field.Set(reflect.ValueOf(value))
return nil
}
} }
switch typ { switch typ {
case typeJSON: case typeJSON:
@ -319,13 +333,15 @@ func randomizeField(s *Seed, field reflect.Value, fieldType string, canBeNull bo
// Retrieve the value to be returned // Retrieve the value to be returned
} else if kind == reflect.Struct { } else if kind == reflect.Struct {
if isNull { if isNull {
value = getStructNullValue(typ) value = getStructNullValue(s, typ)
} else { } else {
value = getStructRandValue(s, typ) value = getStructRandValue(s, typ)
} }
} else { } else {
if isNull { // only get zero values for non byte slices
value = getVariableZeroValue(kind) // to stop mysql from being a jerk
if isNull && kind != reflect.Slice {
value = getVariableZeroValue(s, kind)
} else { } else {
value = getVariableRandValue(s, kind, typ) value = getVariableRandValue(s, kind, typ)
} }
@ -404,10 +420,11 @@ func getArrayRandValue(s *Seed, typ reflect.Type, fieldType string) interface{}
} }
// getStructNullValue for the matching type. // getStructNullValue for the matching type.
func getStructNullValue(typ reflect.Type) interface{} { func getStructNullValue(s *Seed, typ reflect.Type) interface{} {
switch typ { switch typ {
case typeTime: case typeTime:
return time.Time{} // MySQL does not support 0 value time.Time, so use rand
return randDate(s)
case typeNullBool: case typeNullBool:
return null.NewBool(false, false) return null.NewBool(false, false)
case typeNullString: case typeNullString:
@ -463,7 +480,7 @@ func getStructRandValue(s *Seed, typ reflect.Type) interface{} {
case typeNullFloat64: case typeNullFloat64:
return null.NewFloat64(float64(s.nextInt()%10)/10.0+float64(s.nextInt()%10), true) return null.NewFloat64(float64(s.nextInt()%10)/10.0+float64(s.nextInt()%10), true)
case typeNullInt: case typeNullInt:
return null.NewInt(s.nextInt(), true) return null.NewInt(int(int32(s.nextInt())), true)
case typeNullInt8: case typeNullInt8:
return null.NewInt8(int8(s.nextInt()), true) return null.NewInt8(int8(s.nextInt()), true)
case typeNullInt16: case typeNullInt16:
@ -483,14 +500,14 @@ func getStructRandValue(s *Seed, typ reflect.Type) interface{} {
case typeNullUint64: case typeNullUint64:
return null.NewUint64(uint64(s.nextInt()), true) return null.NewUint64(uint64(s.nextInt()), true)
case typeNullBytes: case typeNullBytes:
return null.NewBytes(randByteSlice(s, 16), true) return null.NewBytes(randByteSlice(s, 1), true)
} }
return nil return nil
} }
// getVariableZeroValue for the matching type. // getVariableZeroValue for the matching type.
func getVariableZeroValue(kind reflect.Kind) interface{} { func getVariableZeroValue(s *Seed, kind reflect.Kind) interface{} {
switch kind { switch kind {
case reflect.Float32: case reflect.Float32:
return float32(0) return float32(0)
@ -521,7 +538,7 @@ func getVariableZeroValue(kind reflect.Kind) interface{} {
case reflect.String: case reflect.String:
return "" return ""
case reflect.Slice: case reflect.Slice:
return []byte(nil) return []byte{}
} }
return nil return nil
@ -565,7 +582,7 @@ func getVariableRandValue(s *Seed, kind reflect.Kind, typ reflect.Type) interfac
if sliceVal.Kind() != reflect.Uint8 { if sliceVal.Kind() != reflect.Uint8 {
return errors.Errorf("unsupported slice type: %T, was expecting byte slice.", typ.String()) return errors.Errorf("unsupported slice type: %T, was expecting byte slice.", typ.String())
} }
return randByteSlice(s, 5+s.nextInt()%20) return randByteSlice(s, 1)
} }
return nil return nil

View file

@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"math" "math"
"regexp" "regexp"
"sort"
"strings" "strings"
"sync" "sync"
) )
@ -353,8 +354,15 @@ func MakeStringMap(types map[string]string) string {
buf := GetBuffer() buf := GetBuffer()
defer PutBuffer(buf) defer PutBuffer(buf)
keys := make([]string, 0, len(types))
for k := range types {
keys = append(keys, k)
}
sort.Strings(keys)
c := 0 c := 0
for k, v := range types { for _, k := range keys {
v := types[k]
buf.WriteString(fmt.Sprintf(`"%s": "%s"`, k, v)) buf.WriteString(fmt.Sprintf(`"%s": "%s"`, k, v))
if c < len(types)-1 { if c < len(types)-1 {
buf.WriteString(", ") buf.WriteString(", ")

View file

@ -166,11 +166,10 @@ var templateFunctions = template.FuncMap{
// Database related mangling // Database related mangling
"whereClause": strmangle.WhereClause, "whereClause": strmangle.WhereClause,
// Text helpers // Relationship text helpers
"textsFromForeignKey": textsFromForeignKey, "txtsFromFKey": txtsFromFKey,
"textsFromOneToOneRelationship": textsFromOneToOneRelationship, "txtsFromOneToOne": txtsFromOneToOne,
"textsFromRelationship": textsFromRelationship, "txtsFromToMany": txtsFromToMany,
"preserveDot": preserveDot,
// dbdrivers ops // dbdrivers ops
"filterColumnsByDefault": bdb.FilterColumnsByDefault, "filterColumnsByDefault": bdb.FilterColumnsByDefault,

View file

@ -1,5 +1,4 @@
{{- define "relationship_to_one_struct_helper" -}} {{- define "relationship_to_one_struct_helper" -}}
{{.Function.Name}} *{{.ForeignTable.NameGo}}
{{- end -}} {{- end -}}
{{- $dot := . -}} {{- $dot := . -}}
@ -23,17 +22,19 @@ type {{$modelName}} struct {
// {{$modelNameCamel}}R is where relationships are stored. // {{$modelNameCamel}}R is where relationships are stored.
type {{$modelNameCamel}}R struct { type {{$modelNameCamel}}R struct {
{{range .Table.FKeys -}} {{range .Table.FKeys -}}
{{- $rel := textsFromForeignKey $dot.PkgName $dot.Tables $dot.Table . -}} {{- $txt := txtsFromFKey $dot.Tables $dot.Table . -}}
{{- template "relationship_to_one_struct_helper" $rel}} {{$txt.Function.Name}} *{{$txt.ForeignTable.NameGo}}
{{end -}} {{end -}}
{{- range .Table.ToManyRelationships -}}
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}} {{range .Table.ToOneRelationships -}}
{{- template "relationship_to_one_struct_helper" (textsFromOneToOneRelationship $dot.PkgName $dot.Tables $dot.Table .)}} {{- $txt := txtsFromOneToOne $dot.Tables $dot.Table . -}}
{{else -}} {{$txt.Function.Name}} *{{$txt.ForeignTable.NameGo}}
{{- $rel := textsFromRelationship $dot.Tables $dot.Table . -}} {{end -}}
{{$rel.Function.Name}} {{$rel.ForeignTable.Slice}}
{{end -}}{{/* if ForeignColumnUnique */}} {{range .Table.ToManyRelationships -}}
{{- end -}}{{/* range tomany */}} {{- $txt := txtsFromToMany $dot.Tables $dot.Table . -}}
{{$txt.Function.Name}} {{$txt.ForeignTable.Slice}}
{{end -}}{{/* range tomany */}}
} }
// {{$modelNameCamel}}L is where Load methods for each relationship are stored. // {{$modelNameCamel}}L is where Load methods for each relationship are stored.

View file

@ -13,7 +13,7 @@ type (
// {{$tableNameSingular}}Slice is an alias for a slice of pointers to {{$tableNameSingular}}. // {{$tableNameSingular}}Slice is an alias for a slice of pointers to {{$tableNameSingular}}.
// This should generally be used opposed to []{{$tableNameSingular}}. // This should generally be used opposed to []{{$tableNameSingular}}.
{{$tableNameSingular}}Slice []*{{$tableNameSingular}} {{$tableNameSingular}}Slice []*{{$tableNameSingular}}
{{if eq .NoHooks false -}} {{if not .NoHooks -}}
// {{$tableNameSingular}}Hook is the signature for custom {{$tableNameSingular}} hook methods // {{$tableNameSingular}}Hook is the signature for custom {{$tableNameSingular}} hook methods
{{$tableNameSingular}}Hook func(boil.Executor, *{{$tableNameSingular}}) error {{$tableNameSingular}}Hook func(boil.Executor, *{{$tableNameSingular}}) error
{{- end}} {{- end}}
@ -27,6 +27,7 @@ type (
var ( var (
{{$varNameSingular}}Type = reflect.TypeOf(&{{$tableNameSingular}}{}) {{$varNameSingular}}Type = reflect.TypeOf(&{{$tableNameSingular}}{})
{{$varNameSingular}}Mapping = queries.MakeStructMapping({{$varNameSingular}}Type) {{$varNameSingular}}Mapping = queries.MakeStructMapping({{$varNameSingular}}Type)
{{$varNameSingular}}PrimaryKeyMapping, _ = queries.BindMapping({{$varNameSingular}}Type, {{$varNameSingular}}Mapping, {{$varNameSingular}}PrimaryKeyColumns)
{{$varNameSingular}}InsertCacheMut sync.RWMutex {{$varNameSingular}}InsertCacheMut sync.RWMutex
{{$varNameSingular}}InsertCache = make(map[string]insertCache) {{$varNameSingular}}InsertCache = make(map[string]insertCache)
{{$varNameSingular}}UpdateCacheMut sync.RWMutex {{$varNameSingular}}UpdateCacheMut sync.RWMutex
@ -35,6 +36,10 @@ var (
{{$varNameSingular}}UpsertCache = make(map[string]insertCache) {{$varNameSingular}}UpsertCache = make(map[string]insertCache)
) )
// Force time package dependency for automated UpdatedAt/CreatedAt. var (
var _ = time.Second // Force time package dependency for automated UpdatedAt/CreatedAt.
_ = time.Second
// Force bytes in case of primary key column that uses []byte (for relationship compares)
_ = bytes.MinRead
)
{{end -}} {{end -}}

View file

@ -1,4 +1,4 @@
{{- if eq .NoHooks false -}} {{- if not .NoHooks -}}
{{- $tableNameSingular := .Table.Name | singular | titleCase -}} {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
{{- $varNameSingular := .Table.Name | singular | camelCase -}} {{- $varNameSingular := .Table.Name | singular | camelCase -}}
var {{$varNameSingular}}BeforeInsertHooks []{{$tableNameSingular}}Hook var {{$varNameSingular}}BeforeInsertHooks []{{$tableNameSingular}}Hook

View file

@ -1,34 +1,26 @@
{{- define "relationship_to_one_helper" -}}
{{- $dot := .Dot -}}{{/* .Dot holds the root templateData struct, passed in through preserveDot */}}
{{- with .Rel -}}{{/* Rel holds the text helper data, passed in through preserveDot */}}
{{- $varNameSingular := .ForeignKey.ForeignTable | singular | camelCase -}}
// {{.Function.Name}}G pointed to by the foreign key.
func ({{.Function.Receiver}} *{{.LocalTable.NameGo}}) {{.Function.Name}}G(mods ...qm.QueryMod) {{$varNameSingular}}Query {
return {{.Function.Receiver}}.{{.Function.Name}}(boil.GetDB(), mods...)
}
// {{.Function.Name}} pointed to by the foreign key.
func ({{.Function.Receiver}} *{{.LocalTable.NameGo}}) {{.Function.Name}}(exec boil.Executor, mods ...qm.QueryMod) ({{$varNameSingular}}Query) {
queryMods := []qm.QueryMod{
qm.Where("{{.ForeignTable.ColumnName}}={{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}", {{.Function.Receiver}}.{{.LocalTable.ColumnNameGo}}),
}
queryMods = append(queryMods, mods...)
query := {{.ForeignTable.NamePluralGo}}(exec, queryMods...)
queries.SetFrom(query.Query, "{{.ForeignTable.Name | $dot.SchemaTable}}")
return query
}
{{- end -}}{{/* end with */}}
{{end -}}{{/* end define */}}
{{- /* Begin execution of template for one-to-one relationship */ -}}
{{- if .Table.IsJoinTable -}} {{- if .Table.IsJoinTable -}}
{{- else -}} {{- else -}}
{{- $dot := . -}} {{- $dot := . -}}
{{- range .Table.FKeys -}} {{- range .Table.FKeys -}}
{{- $txt := textsFromForeignKey $dot.PkgName $dot.Tables $dot.Table . -}} {{- $txt := txtsFromFKey $dot.Tables $dot.Table . -}}
{{- template "relationship_to_one_helper" (preserveDot $dot $txt) -}} {{- $varNameSingular := .ForeignTable | singular | camelCase}}
// {{$txt.Function.Name}}G pointed to by the foreign key.
func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}G(mods ...qm.QueryMod) {{$varNameSingular}}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) {
queryMods := []qm.QueryMod{
qm.Where("{{$txt.ForeignTable.ColumnName}}={{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}", o.{{$txt.LocalTable.ColumnNameGo}}),
}
queryMods = append(queryMods, mods...)
query := {{$txt.ForeignTable.NamePluralGo}}(exec, queryMods...)
queries.SetFrom(query.Query, "{{.ForeignTable | $dot.SchemaTable}}")
return query
}
{{- end -}} {{- end -}}
{{- end -}} {{- end -}}

View file

@ -0,0 +1,26 @@
{{- if .Table.IsJoinTable -}}
{{- else -}}
{{- $dot := . -}}
{{- range .Table.ToOneRelationships -}}
{{- $txt := txtsFromOneToOne $dot.Tables $dot.Table . -}}
{{- $varNameSingular := .ForeignTable | singular | camelCase}}
// {{$txt.Function.Name}}G pointed to by the foreign key.
func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}G(mods ...qm.QueryMod) {{$varNameSingular}}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) {
queryMods := []qm.QueryMod{
qm.Where("{{$txt.ForeignTable.ColumnName}}={{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}", o.{{$txt.LocalTable.ColumnNameGo}}),
}
queryMods = append(queryMods, mods...)
query := {{$txt.ForeignTable.NamePluralGo}}(exec, queryMods...)
queries.SetFrom(query.Query, "{{.ForeignTable | $dot.SchemaTable}}")
return query
}
{{- end -}}
{{- end -}}

View file

@ -1,27 +1,20 @@
{{- /* Begin execution of template for many-to-one or many-to-many relationship helper */ -}}
{{- if .Table.IsJoinTable -}} {{- if .Table.IsJoinTable -}}
{{- else -}} {{- else -}}
{{- $dot := . -}} {{- $dot := . -}}
{{- $table := .Table -}} {{- $table := .Table -}}
{{- range .Table.ToManyRelationships -}} {{- range .Table.ToManyRelationships -}}
{{- $varNameSingular := .ForeignTable | singular | camelCase -}} {{- $varNameSingular := .ForeignTable | singular | camelCase -}}
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}} {{- $rel := txtsFromToMany $dot.Tables $table . -}}
{{- /* Begin execution of template for many-to-one relationship. */ -}} {{- $schemaForeignTable := .ForeignTable | $dot.SchemaTable -}}
{{- $txt := textsFromOneToOneRelationship $dot.PkgName $dot.Tables $table . -}}
{{- template "relationship_to_one_helper" (preserveDot $dot $txt) -}}
{{- else -}}
{{- /* Begin execution of template for many-to-many relationship. */ -}}
{{- $rel := textsFromRelationship $dot.Tables $table . -}}
{{- $schemaForeignTable := .ForeignTable | $dot.SchemaTable -}}
// {{$rel.Function.Name}}G retrieves all the {{$rel.LocalTable.NameSingular}}'s {{$rel.ForeignTable.NameHumanReadable}} // {{$rel.Function.Name}}G retrieves all the {{$rel.LocalTable.NameSingular}}'s {{$rel.ForeignTable.NameHumanReadable}}
{{- if not (eq $rel.Function.Name $rel.ForeignTable.NamePluralGo)}} via {{.ForeignColumn}} column{{- end}}. {{- if not (eq $rel.Function.Name $rel.ForeignTable.NamePluralGo)}} via {{.ForeignColumn}} column{{- end}}.
func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) {{$rel.Function.Name}}G(mods ...qm.QueryMod) {{$varNameSingular}}Query { func (o *{{$rel.LocalTable.NameGo}}) {{$rel.Function.Name}}G(mods ...qm.QueryMod) {{$varNameSingular}}Query {
return {{$rel.Function.Receiver}}.{{$rel.Function.Name}}(boil.GetDB(), mods...) return o.{{$rel.Function.Name}}(boil.GetDB(), mods...)
} }
// {{$rel.Function.Name}} retrieves all the {{$rel.LocalTable.NameSingular}}'s {{$rel.ForeignTable.NameHumanReadable}} with an executor // {{$rel.Function.Name}} retrieves all the {{$rel.LocalTable.NameSingular}}'s {{$rel.ForeignTable.NameHumanReadable}} with an executor
{{- if not (eq $rel.Function.Name $rel.ForeignTable.NamePluralGo)}} via {{.ForeignColumn}} column{{- end}}. {{- if not (eq $rel.Function.Name $rel.ForeignTable.NamePluralGo)}} via {{.ForeignColumn}} column{{- end}}.
func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) {{$rel.Function.Name}}(exec boil.Executor, mods ...qm.QueryMod) {{$varNameSingular}}Query { func (o *{{$rel.LocalTable.NameGo}}) {{$rel.Function.Name}}(exec boil.Executor, mods ...qm.QueryMod) {{$varNameSingular}}Query {
queryMods := []qm.QueryMod{ queryMods := []qm.QueryMod{
qm.Select("{{id 0 | $dot.Quotes}}.*"), qm.Select("{{id 0 | $dot.Quotes}}.*"),
} }
@ -33,11 +26,11 @@ func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) {{$rel.Function.Na
{{if .ToJoinTable -}} {{if .ToJoinTable -}}
queryMods = append(queryMods, 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.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}}={{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}", {{$rel.Function.Receiver}}.{{$rel.LocalTable.ColumnNameGo}}), qm.Where("{{id 1 | $dot.Quotes}}.{{.JoinLocalColumn | $dot.Quotes}}={{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}", o.{{$rel.LocalTable.ColumnNameGo}}),
) )
{{else -}} {{else -}}
queryMods = append(queryMods, queryMods = append(queryMods,
qm.Where("{{id 0 | $dot.Quotes}}.{{.ForeignColumn | $dot.Quotes}}={{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}", {{$rel.Function.Receiver}}.{{$rel.LocalTable.ColumnNameGo}}), qm.Where("{{id 0 | $dot.Quotes}}.{{.ForeignColumn | $dot.Quotes}}={{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}", o.{{$rel.LocalTable.ColumnNameGo}}),
) )
{{end}} {{end}}
@ -46,6 +39,5 @@ func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) {{$rel.Function.Na
return query return query
} }
{{end -}}{{- /* if unique foreign key */ -}} {{end -}}{{- /* range relationships */ -}}
{{- end -}}{{- /* range relationships */ -}}
{{- end -}}{{- /* if isJoinTable */ -}} {{- end -}}{{- /* if isJoinTable */ -}}

View file

@ -1,93 +0,0 @@
{{- define "relationship_to_one_eager_helper" -}}
{{- $dot := .Dot -}}{{/* .Dot holds the root templateData struct, passed in through preserveDot */}}
{{- $varNameSingular := $dot.Table.Name | singular | camelCase -}}
{{- with .Rel -}}
{{- $arg := printf "maybe%s" .LocalTable.NameGo -}}
{{- $slice := printf "%sSlice" .LocalTable.NameGo -}}
// Load{{.Function.Name}} allows an eager lookup of values, cached into the
// loaded structs of the objects.
func ({{$varNameSingular}}L) Load{{.Function.Name}}(e boil.Executor, singular bool, {{$arg}} interface{}) error {
var slice []*{{.LocalTable.NameGo}}
var object *{{.LocalTable.NameGo}}
count := 1
if singular {
object = {{$arg}}.(*{{.LocalTable.NameGo}})
} else {
slice = *{{$arg}}.(*{{$slice}})
count = len(slice)
}
args := make([]interface{}, count)
if singular {
args[0] = object.{{.LocalTable.ColumnNameGo}}
} else {
for i, obj := range slice {
args[i] = obj.{{.LocalTable.ColumnNameGo}}
}
}
query := fmt.Sprintf(
"select * from {{.ForeignKey.ForeignTable | $dot.SchemaTable}} where {{.ForeignKey.ForeignColumn | $dot.Quotes}} in (%s)",
strmangle.Placeholders(dialect.IndexPlaceholders, count, 1, 1),
)
if boil.DebugMode {
fmt.Fprintf(boil.DebugWriter, "%s\n%v\n", query, args)
}
results, err := e.Query(query, args...)
if err != nil {
return errors.Wrap(err, "failed to eager load {{.ForeignTable.NameGo}}")
}
defer results.Close()
var resultSlice []*{{.ForeignTable.NameGo}}
if err = queries.Bind(results, &resultSlice); err != nil {
return errors.Wrap(err, "failed to bind eager loaded slice {{.ForeignTable.NameGo}}")
}
{{if not $dot.NoHooks -}}
if len({{.ForeignTable.Name | singular | camelCase}}AfterSelectHooks) != 0 {
for _, obj := range resultSlice {
if err := obj.doAfterSelectHooks(e); err != nil {
return err
}
}
}
{{- end}}
if singular && len(resultSlice) != 0 {
if object.R == nil {
object.R = &{{$varNameSingular}}R{}
}
object.R.{{.Function.Name}} = resultSlice[0]
return nil
}
for _, foreign := range resultSlice {
for _, local := range slice {
if local.{{.Function.LocalAssignment}} == foreign.{{.Function.ForeignAssignment}} {
if local.R == nil {
local.R = &{{$varNameSingular}}R{}
}
local.R.{{.Function.Name}} = foreign
break
}
}
}
return nil
}
{{- end -}}{{- /* end with */ -}}
{{end -}}{{- /* end define */ -}}
{{- /* Begin execution of template for one-to-one eager load */ -}}
{{- if .Table.IsJoinTable -}}
{{- else -}}
{{- $dot := . -}}
{{- range .Table.FKeys -}}
{{- $txt := textsFromForeignKey $dot.PkgName $dot.Tables $dot.Table . -}}
{{- template "relationship_to_one_eager_helper" (preserveDot $dot $txt) -}}
{{- end -}}
{{end}}

View file

@ -0,0 +1,89 @@
{{- if .Table.IsJoinTable -}}
{{- else -}}
{{- $dot := . -}}
{{- range .Table.FKeys -}}
{{- $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 {
var slice []*{{$txt.LocalTable.NameGo}}
var object *{{$txt.LocalTable.NameGo}}
count := 1
if singular {
object = {{$arg}}.(*{{$txt.LocalTable.NameGo}})
} else {
slice = *{{$arg}}.(*{{$slice}})
count = len(slice)
}
args := make([]interface{}, count)
if singular {
args[0] = object.{{$txt.LocalTable.ColumnNameGo}}
} else {
for i, obj := range slice {
args[i] = obj.{{$txt.LocalTable.ColumnNameGo}}
}
}
query := fmt.Sprintf(
"select * from {{.ForeignTable | $dot.SchemaTable}} where {{.ForeignColumn | $dot.Quotes}} in (%s)",
strmangle.Placeholders(dialect.IndexPlaceholders, count, 1, 1),
)
if boil.DebugMode {
fmt.Fprintf(boil.DebugWriter, "%s\n%v\n", query, args)
}
results, err := e.Query(query, args...)
if err != nil {
return errors.Wrap(err, "failed to eager load {{$txt.ForeignTable.NameGo}}")
}
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}}")
}
{{if not $dot.NoHooks -}}
if len({{$varNameSingular}}AfterSelectHooks) != 0 {
for _, obj := range resultSlice {
if err := obj.doAfterSelectHooks(e); err != nil {
return err
}
}
}
{{- end}}
if singular && len(resultSlice) != 0 {
if object.R == nil {
object.R = &{{$varNameSingular}}R{}
}
object.R.{{$txt.Function.Name}} = resultSlice[0]
return nil
}
for _, foreign := range resultSlice {
for _, local := range slice {
{{if $txt.Function.UsesBytes -}}
if 0 == bytes.Compare(local.{{$txt.Function.LocalAssignment}}, foreign.{{$txt.Function.ForeignAssignment}}) {
{{else -}}
if local.{{$txt.Function.LocalAssignment}} == foreign.{{$txt.Function.ForeignAssignment}} {
{{end -}}
if local.R == nil {
local.R = &{{$varNameSingular}}R{}
}
local.R.{{$txt.Function.Name}} = foreign
break
}
}
}
return nil
}
{{end -}}{{/* range */}}
{{end}}{{/* join table */}}

View file

@ -0,0 +1,89 @@
{{- if .Table.IsJoinTable -}}
{{- else -}}
{{- $dot := . -}}
{{- range .Table.ToOneRelationships -}}
{{- $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 {
var slice []*{{$txt.LocalTable.NameGo}}
var object *{{$txt.LocalTable.NameGo}}
count := 1
if singular {
object = {{$arg}}.(*{{$txt.LocalTable.NameGo}})
} else {
slice = *{{$arg}}.(*{{$slice}})
count = len(slice)
}
args := make([]interface{}, count)
if singular {
args[0] = object.{{$txt.LocalTable.ColumnNameGo}}
} else {
for i, obj := range slice {
args[i] = obj.{{$txt.LocalTable.ColumnNameGo}}
}
}
query := fmt.Sprintf(
"select * from {{.ForeignTable | $dot.SchemaTable}} where {{.ForeignColumn | $dot.Quotes}} in (%s)",
strmangle.Placeholders(dialect.IndexPlaceholders, count, 1, 1),
)
if boil.DebugMode {
fmt.Fprintf(boil.DebugWriter, "%s\n%v\n", query, args)
}
results, err := e.Query(query, args...)
if err != nil {
return errors.Wrap(err, "failed to eager load {{$txt.ForeignTable.NameGo}}")
}
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}}")
}
{{if not $dot.NoHooks -}}
if len({{$varNameSingular}}AfterSelectHooks) != 0 {
for _, obj := range resultSlice {
if err := obj.doAfterSelectHooks(e); err != nil {
return err
}
}
}
{{- end}}
if singular && len(resultSlice) != 0 {
if object.R == nil {
object.R = &{{$varNameSingular}}R{}
}
object.R.{{$txt.Function.Name}} = resultSlice[0]
return nil
}
for _, foreign := range resultSlice {
for _, local := range slice {
{{if $txt.Function.UsesBytes -}}
if 0 == bytes.Compare(local.{{$txt.Function.LocalAssignment}}, foreign.{{$txt.Function.ForeignAssignment}}) {
{{else -}}
if local.{{$txt.Function.LocalAssignment}} == foreign.{{$txt.Function.ForeignAssignment}} {
{{end -}}
if local.R == nil {
local.R = &{{$varNameSingular}}R{}
}
local.R.{{$txt.Function.Name}} = foreign
break
}
}
}
return nil
}
{{end -}}{{/* range */}}
{{end}}{{/* join table */}}

View file

@ -1,105 +0,0 @@
{{- define "relationship_to_one_setops_helper" -}}
{{- $tmplData := .Dot -}}{{/* .Dot holds the root templateData struct, passed in through preserveDot */}}
{{- with .Rel -}}
{{- $varNameSingular := .ForeignKey.ForeignTable | singular | camelCase -}}
{{- $localNameSingular := .ForeignKey.Table | singular | camelCase}}
// Set{{.Function.Name}} of the {{.ForeignKey.Table | singular}} to the related item.
// Sets {{.Function.Receiver}}.R.{{.Function.Name}} to related.
// Adds {{.Function.Receiver}} to related.R.{{.Function.ForeignName}}.
func ({{.Function.Receiver}} *{{.LocalTable.NameGo}}) Set{{.Function.Name}}(exec boil.Executor, insert bool, related *{{.ForeignTable.NameGo}}) error {
var err error
if insert {
if err = related.Insert(exec); err != nil {
return errors.Wrap(err, "failed to insert into foreign table")
}
}
oldVal := {{.Function.Receiver}}.{{.LocalTable.ColumnNameGo}}
{{.Function.Receiver}}.{{.Function.LocalAssignment}} = related.{{.Function.ForeignAssignment}}
if err = {{.Function.Receiver}}.Update(exec, "{{.ForeignKey.Column}}"); err != nil {
{{.Function.Receiver}}.{{.LocalTable.ColumnNameGo}} = oldVal
return errors.Wrap(err, "failed to update local table")
}
if {{.Function.Receiver}}.R == nil {
{{.Function.Receiver}}.R = &{{$localNameSingular}}R{
{{.Function.Name}}: related,
}
} else {
{{.Function.Receiver}}.R.{{.Function.Name}} = related
}
{{if (or .ForeignKey.Unique .Function.OneToOne) -}}
if related.R == nil {
related.R = &{{$varNameSingular}}R{
{{.Function.ForeignName}}: {{.Function.Receiver}},
}
} else {
related.R.{{.Function.ForeignName}} = {{.Function.Receiver}}
}
{{else -}}
if related.R == nil {
related.R = &{{$varNameSingular}}R{
{{.Function.ForeignName}}: {{.LocalTable.NameGo}}Slice{{"{"}}{{.Function.Receiver}}{{"}"}},
}
} else {
related.R.{{.Function.ForeignName}} = append(related.R.{{.Function.ForeignName}}, {{.Function.Receiver}})
}
{{end -}}
{{if .ForeignKey.Nullable}}
{{.Function.Receiver}}.{{.LocalTable.ColumnNameGo}}.Valid = true
{{end -}}
return nil
}
{{- if .ForeignKey.Nullable}}
// Remove{{.Function.Name}} relationship.
// Sets {{.Function.Receiver}}.R.{{.Function.Name}} to nil.
// Removes {{.Function.Receiver}} from all passed in related items' relationships struct (Optional).
func ({{.Function.Receiver}} *{{.LocalTable.NameGo}}) Remove{{.Function.Name}}(exec boil.Executor, related *{{.ForeignTable.NameGo}}) error {
var err error
{{.Function.Receiver}}.{{.LocalTable.ColumnNameGo}}.Valid = false
if err = {{.Function.Receiver}}.Update(exec, "{{.ForeignKey.Column}}"); err != nil {
{{.Function.Receiver}}.{{.LocalTable.ColumnNameGo}}.Valid = true
return errors.Wrap(err, "failed to update local table")
}
{{.Function.Receiver}}.R.{{.Function.Name}} = nil
if related == nil || related.R == nil {
return nil
}
{{if .ForeignKey.Unique -}}
related.R.{{.Function.ForeignName}} = nil
{{else -}}
for i, ri := range related.R.{{.Function.ForeignName}} {
if {{.Function.Receiver}}.{{.Function.LocalAssignment}} != ri.{{.Function.LocalAssignment}} {
continue
}
ln := len(related.R.{{.Function.ForeignName}})
if ln > 1 && i < ln-1 {
related.R.{{.Function.ForeignName}}[i] = related.R.{{.Function.ForeignName}}[ln-1]
}
related.R.{{.Function.ForeignName}} = related.R.{{.Function.ForeignName}}[:ln-1]
break
}
{{end -}}
return nil
}
{{- end -}}{{/* if foreignkey nullable */}}
{{end -}}{{/* end with */}}
{{- end -}}{{/* end define */}}
{{- /* Begin execution of template for one-to-one setops */ -}}
{{- if .Table.IsJoinTable -}}
{{- else -}}
{{- $dot := . -}}
{{- range .Table.FKeys -}}
{{- $txt := textsFromForeignKey $dot.PkgName $dot.Tables $dot.Table . -}}
{{- template "relationship_to_one_setops_helper" (preserveDot $dot $txt) -}}
{{- end -}}
{{- end -}}

View file

@ -3,17 +3,11 @@
{{- else -}} {{- else -}}
{{- $dot := . -}} {{- $dot := . -}}
{{- range .Table.ToManyRelationships -}} {{- range .Table.ToManyRelationships -}}
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}} {{- $varNameSingular := $dot.Table.Name | singular | camelCase -}}
{{- /* Begin execution of template for many-to-one eager load */ -}} {{- $txt := txtsFromToMany $dot.Tables $dot.Table . -}}
{{- $txt := textsFromOneToOneRelationship $dot.PkgName $dot.Tables $dot.Table . -}} {{- $arg := printf "maybe%s" $txt.LocalTable.NameGo -}}
{{- template "relationship_to_one_eager_helper" (preserveDot $dot $txt) -}} {{- $slice := printf "%sSlice" $txt.LocalTable.NameGo -}}
{{- else -}} {{- $schemaForeignTable := .ForeignTable | $dot.SchemaTable}}
{{- /* Begin execution of template for many-to-many eager load */ -}}
{{- $varNameSingular := $dot.Table.Name | singular | camelCase -}}
{{- $txt := textsFromRelationship $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 // Load{{$txt.Function.Name}} allows an eager lookup of values, cached into the
// loaded structs of the objects. // loaded structs of the objects.
func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singular bool, {{$arg}} interface{}) error { func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singular bool, {{$arg}} interface{}) error {
@ -110,7 +104,11 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
for i, foreign := range resultSlice { for i, foreign := range resultSlice {
localJoinCol := localJoinCols[i] localJoinCol := localJoinCols[i]
for _, local := range slice { for _, local := range slice {
{{if $txt.Function.UsesBytes -}}
if 0 == bytes.Compare(local.{{$txt.Function.LocalAssignment}}, localJoinCol) {
{{else -}}
if local.{{$txt.Function.LocalAssignment}} == localJoinCol { if local.{{$txt.Function.LocalAssignment}} == localJoinCol {
{{end -}}
if local.R == nil { if local.R == nil {
local.R = &{{$varNameSingular}}R{} local.R = &{{$varNameSingular}}R{}
} }
@ -122,7 +120,11 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
{{else -}} {{else -}}
for _, foreign := range resultSlice { for _, foreign := range resultSlice {
for _, local := range slice { for _, local := range slice {
{{if $txt.Function.UsesBytes -}}
if 0 == bytes.Compare(local.{{$txt.Function.LocalAssignment}}, foreign.{{$txt.Function.ForeignAssignment}}) {
{{else -}}
if local.{{$txt.Function.LocalAssignment}} == foreign.{{$txt.Function.ForeignAssignment}} { if local.{{$txt.Function.LocalAssignment}} == foreign.{{$txt.Function.ForeignAssignment}} {
{{end -}}
if local.R == nil { if local.R == nil {
local.R = &{{$varNameSingular}}R{} local.R = &{{$varNameSingular}}R{}
} }
@ -136,6 +138,5 @@ func ({{$varNameSingular}}L) Load{{$txt.Function.Name}}(e boil.Executor, singula
return nil return nil
} }
{{end -}}{{/* if ForeignColumnUnique */}} {{end -}}{{/* range tomany */}}
{{- end -}}{{/* range tomany */}}
{{- end -}}{{/* if IsJoinTable */}} {{- end -}}{{/* if IsJoinTable */}}

View file

@ -0,0 +1,105 @@
{{- /* Begin execution of template for one-to-one setops */ -}}
{{- if .Table.IsJoinTable -}}
{{- else -}}
{{- $dot := . -}}
{{- range .Table.FKeys -}}
{{- $txt := txtsFromFKey $dot.Tables $dot.Table . -}}
{{- $varNameSingular := .ForeignTable | singular | camelCase -}}
{{- $localNameSingular := .Table | singular | camelCase}}
// 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}}.
func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executor, insert bool, related *{{$txt.ForeignTable.NameGo}}) error {
var err error
if insert {
if err = related.Insert(exec); err != nil {
return errors.Wrap(err, "failed to insert into foreign table")
}
}
oldVal := o.{{$txt.Function.LocalAssignment}}
o.{{$txt.Function.LocalAssignment}} = related.{{$txt.Function.ForeignAssignment}}
{{if .Nullable -}}
o.{{$txt.LocalTable.ColumnNameGo}}.Valid = true
{{- end}}
if err = o.Update(exec, "{{.Column}}"); err != nil {
o.{{$txt.Function.LocalAssignment}} = oldVal
{{if .Nullable -}}
o.{{$txt.LocalTable.ColumnNameGo}}.Valid = false
{{- end}}
return errors.Wrap(err, "failed to update local table")
}
if o.R == nil {
o.R = &{{$localNameSingular}}R{
{{$txt.Function.Name}}: related,
}
} else {
o.R.{{$txt.Function.Name}} = related
}
{{if .Unique -}}
if related.R == nil {
related.R = &{{$varNameSingular}}R{
{{$txt.Function.ForeignName}}: o,
}
} else {
related.R.{{$txt.Function.ForeignName}} = o
}
{{else -}}
if related.R == nil {
related.R = &{{$varNameSingular}}R{
{{$txt.Function.ForeignName}}: {{$txt.LocalTable.NameGo}}Slice{{"{"}}o{{"}"}},
}
} else {
related.R.{{$txt.Function.ForeignName}} = append(related.R.{{$txt.Function.ForeignName}}, o)
}
{{- end}}
return nil
}
{{- if .Nullable}}
// Remove{{$txt.Function.Name}} relationship.
// Sets o.R.{{$txt.Function.Name}} to nil.
// Removes o from all passed in related items' relationships struct (Optional).
func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}(exec boil.Executor, related *{{$txt.ForeignTable.NameGo}}) error {
var err error
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")
}
o.R.{{$txt.Function.Name}} = nil
if related == nil || related.R == nil {
return nil
}
{{if .Unique -}}
related.R.{{$txt.Function.ForeignName}} = nil
{{else -}}
for i, ri := range related.R.{{$txt.Function.ForeignName}} {
{{if $txt.Function.UsesBytes -}}
if 0 != bytes.Compare(o.{{$txt.Function.LocalAssignment}}, ri.{{$txt.Function.LocalAssignment}}) {
{{else -}}
if o.{{$txt.Function.LocalAssignment}} != ri.{{$txt.Function.LocalAssignment}} {
{{end -}}
continue
}
ln := len(related.R.{{$txt.Function.ForeignName}})
if ln > 1 && i < ln-1 {
related.R.{{$txt.Function.ForeignName}}[i] = related.R.{{$txt.Function.ForeignName}}[ln-1]
}
related.R.{{$txt.Function.ForeignName}} = related.R.{{$txt.Function.ForeignName}}[:ln-1]
break
}
{{end -}}
return nil
}
{{end -}}{{/* if foreignkey nullable */}}
{{- end -}}{{/* range */}}
{{- end -}}{{/* join table */}}

View file

@ -0,0 +1,79 @@
{{- if .Table.IsJoinTable -}}
{{- else -}}
{{- $dot := . -}}
{{- range .Table.ToOneRelationships -}}
{{- $txt := txtsFromOneToOne $dot.Tables $dot.Table . -}}
{{- $varNameSingular := .ForeignTable | singular | camelCase -}}
{{- $localNameSingular := .Table | singular | camelCase}}
// 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}}.
func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executor, insert bool, related *{{$txt.ForeignTable.NameGo}}) error {
var err error
oldVal := related.{{$txt.Function.ForeignAssignment}}
related.{{$txt.Function.ForeignAssignment}} = o.{{$txt.Function.LocalAssignment}}
{{if .ForeignColumnNullable -}}
related.{{$txt.ForeignTable.ColumnNameGo}}.Valid = true
{{- end}}
if insert {
if err = related.Insert(exec); err != nil {
related.{{$txt.Function.ForeignAssignment}} = oldVal
{{if .ForeignColumnNullable -}}
related.{{$txt.ForeignTable.ColumnNameGo}}.Valid = false
{{- end}}
return errors.Wrap(err, "failed to insert into foreign table")
}
} else {
if err = related.Update(exec, "{{.ForeignColumn}}"); err != nil {
related.{{$txt.Function.ForeignAssignment}} = oldVal
{{if .ForeignColumnNullable -}}
related.{{$txt.ForeignTable.ColumnNameGo}}.Valid = false
{{- end}}
return errors.Wrap(err, "failed to update foreign table")
}
}
if o.R == nil {
o.R = &{{$localNameSingular}}R{
{{$txt.Function.Name}}: related,
}
} else {
o.R.{{$txt.Function.Name}} = related
}
if related.R == nil {
related.R = &{{$varNameSingular}}R{
{{$txt.Function.ForeignName}}: o,
}
} else {
related.R.{{$txt.Function.ForeignName}} = o
}
return nil
}
{{- if .ForeignColumnNullable}}
// Remove{{$txt.Function.Name}} relationship.
// Sets o.R.{{$txt.Function.Name}} to nil.
// Removes o from all passed in related items' relationships struct (Optional).
func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}(exec boil.Executor, related *{{$txt.ForeignTable.NameGo}}) error {
var err error
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")
}
o.R.{{$txt.Function.Name}} = nil
if related == nil || related.R == nil {
return nil
}
related.R.{{$txt.Function.ForeignName}} = nil
return nil
}
{{end -}}{{/* if foreignkey nullable */}}
{{- end -}}{{/* range */}}
{{- end -}}{{/* join table */}}

View file

@ -4,24 +4,18 @@
{{- $dot := . -}} {{- $dot := . -}}
{{- $table := .Table -}} {{- $table := .Table -}}
{{- range .Table.ToManyRelationships -}} {{- range .Table.ToManyRelationships -}}
{{- $varNameSingular := .ForeignTable | singular | camelCase -}} {{- $rel := txtsFromToMany $dot.Tables $table . -}}
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}} {{- $varNameSingular := .Table | singular | camelCase -}}
{{- /* Begin execution of template for many-to-one setops */ -}} {{- $foreignVarNameSingular := .ForeignTable | singular | camelCase}}
{{- $txt := textsFromOneToOneRelationship $dot.PkgName $dot.Tables $table . -}}
{{- template "relationship_to_one_setops_helper" (preserveDot $dot $txt) -}}
{{- else -}}
{{- $rel := textsFromRelationship $dot.Tables $table . -}}
{{- $localNameSingular := .Table | singular | camelCase -}}
{{- $foreignNameSingular := .ForeignTable | singular | camelCase}}
// Add{{$rel.Function.Name}} adds the given related objects to the existing relationships // Add{{$rel.Function.Name}} adds the given related objects to the existing relationships
// of the {{$table.Name | singular}}, optionally inserting them as new records. // of the {{$table.Name | singular}}, optionally inserting them as new records.
// Appends related to {{$rel.Function.Receiver}}.R.{{$rel.Function.Name}}. // Appends related to o.R.{{$rel.Function.Name}}.
// Sets related.R.{{$rel.Function.ForeignName}} appropriately. // Sets related.R.{{$rel.Function.ForeignName}} appropriately.
func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) Add{{$rel.Function.Name}}(exec boil.Executor, insert bool, related ...*{{$rel.ForeignTable.NameGo}}) error { func (o *{{$rel.LocalTable.NameGo}}) Add{{$rel.Function.Name}}(exec boil.Executor, insert bool, related ...*{{$rel.ForeignTable.NameGo}}) error {
var err error var err error
for _, rel := range related { for _, rel := range related {
{{if not .ToJoinTable -}} {{if not .ToJoinTable -}}
rel.{{$rel.Function.ForeignAssignment}} = {{$rel.Function.Receiver}}.{{$rel.Function.LocalAssignment}} rel.{{$rel.Function.ForeignAssignment}} = o.{{$rel.Function.LocalAssignment}}
{{if .ForeignColumnNullable -}} {{if .ForeignColumnNullable -}}
rel.{{$rel.ForeignTable.ColumnNameGo}}.Valid = true rel.{{$rel.ForeignTable.ColumnNameGo}}.Valid = true
{{end -}} {{end -}}
@ -40,7 +34,7 @@ func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) Add{{$rel.Function
{{if .ToJoinTable -}} {{if .ToJoinTable -}}
for _, rel := range related { for _, rel := range related {
query := "insert into {{.JoinTable | $dot.SchemaTable}} ({{.JoinLocalColumn | $dot.Quotes}}, {{.JoinForeignColumn | $dot.Quotes}}) values {{if $dot.Dialect.IndexPlaceholders}}($1, $2){{else}}(?, ?){{end}}" query := "insert into {{.JoinTable | $dot.SchemaTable}} ({{.JoinLocalColumn | $dot.Quotes}}, {{.JoinForeignColumn | $dot.Quotes}}) values {{if $dot.Dialect.IndexPlaceholders}}($1, $2){{else}}(?, ?){{end}}"
values := []interface{}{{"{"}}{{$rel.Function.Receiver}}.{{$rel.LocalTable.ColumnNameGo}}, rel.{{$rel.ForeignTable.ColumnNameGo}}} values := []interface{}{{"{"}}o.{{$rel.LocalTable.ColumnNameGo}}, rel.{{$rel.ForeignTable.ColumnNameGo}}}
if boil.DebugMode { if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, query) fmt.Fprintln(boil.DebugWriter, query)
@ -54,32 +48,32 @@ func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) Add{{$rel.Function
} }
{{end -}} {{end -}}
if {{$rel.Function.Receiver}}.R == nil { if o.R == nil {
{{$rel.Function.Receiver}}.R = &{{$localNameSingular}}R{ o.R = &{{$varNameSingular}}R{
{{$rel.Function.Name}}: related, {{$rel.Function.Name}}: related,
} }
} else { } else {
{{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} = append({{$rel.Function.Receiver}}.R.{{$rel.Function.Name}}, related...) o.R.{{$rel.Function.Name}} = append(o.R.{{$rel.Function.Name}}, related...)
} }
{{if .ToJoinTable -}} {{if .ToJoinTable -}}
for _, rel := range related { for _, rel := range related {
if rel.R == nil { if rel.R == nil {
rel.R = &{{$foreignNameSingular}}R{ rel.R = &{{$foreignVarNameSingular}}R{
{{$rel.Function.ForeignName}}: {{$rel.LocalTable.NameGo}}Slice{{"{"}}{{$rel.Function.Receiver}}{{"}"}}, {{$rel.Function.ForeignName}}: {{$rel.LocalTable.NameGo}}Slice{{"{"}}o{{"}"}},
} }
} else { } else {
rel.R.{{$rel.Function.ForeignName}} = append(rel.R.{{$rel.Function.ForeignName}}, {{$rel.Function.Receiver}}) rel.R.{{$rel.Function.ForeignName}} = append(rel.R.{{$rel.Function.ForeignName}}, o)
} }
} }
{{else -}} {{else -}}
for _, rel := range related { for _, rel := range related {
if rel.R == nil { if rel.R == nil {
rel.R = &{{$foreignNameSingular}}R{ rel.R = &{{$foreignVarNameSingular}}R{
{{$rel.Function.ForeignName}}: {{$rel.Function.Receiver}}, {{$rel.Function.ForeignName}}: o,
} }
} else { } else {
rel.R.{{$rel.Function.ForeignName}} = {{$rel.Function.Receiver}} rel.R.{{$rel.Function.ForeignName}} = o
} }
} }
{{end -}} {{end -}}
@ -91,16 +85,16 @@ func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) Add{{$rel.Function
// Set{{$rel.Function.Name}} removes all previously related items of the // Set{{$rel.Function.Name}} removes all previously related items of the
// {{$table.Name | singular}} replacing them completely with the passed // {{$table.Name | singular}} replacing them completely with the passed
// in related items, optionally inserting them as new records. // in related items, optionally inserting them as new records.
// Sets {{$rel.Function.Receiver}}.R.{{$rel.Function.ForeignName}}'s {{$rel.Function.Name}} accordingly. // Sets o.R.{{$rel.Function.ForeignName}}'s {{$rel.Function.Name}} accordingly.
// Replaces {{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} with related. // Replaces o.R.{{$rel.Function.Name}} with related.
// Sets related.R.{{$rel.Function.ForeignName}}'s {{$rel.Function.Name}} accordingly. // Sets related.R.{{$rel.Function.ForeignName}}'s {{$rel.Function.Name}} accordingly.
func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) Set{{$rel.Function.Name}}(exec boil.Executor, insert bool, related ...*{{$rel.ForeignTable.NameGo}}) error { func (o *{{$rel.LocalTable.NameGo}}) Set{{$rel.Function.Name}}(exec boil.Executor, insert bool, related ...*{{$rel.ForeignTable.NameGo}}) error {
{{if .ToJoinTable -}} {{if .ToJoinTable -}}
query := "delete from {{.JoinTable | $dot.SchemaTable}} where {{.JoinLocalColumn | $dot.Quotes}} = {{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}" query := "delete from {{.JoinTable | $dot.SchemaTable}} where {{.JoinLocalColumn | $dot.Quotes}} = {{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}"
values := []interface{}{{"{"}}{{$rel.Function.Receiver}}.{{$rel.LocalTable.ColumnNameGo}}} values := []interface{}{{"{"}}o.{{$rel.LocalTable.ColumnNameGo}}}
{{else -}} {{else -}}
query := "update {{.ForeignTable | $dot.SchemaTable}} set {{.ForeignColumn | $dot.Quotes}} = null where {{.ForeignColumn | $dot.Quotes}} = {{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}" query := "update {{.ForeignTable | $dot.SchemaTable}} set {{.ForeignColumn | $dot.Quotes}} = null where {{.ForeignColumn | $dot.Quotes}} = {{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}"
values := []interface{}{{"{"}}{{$rel.Function.Receiver}}.{{$rel.LocalTable.ColumnNameGo}}} values := []interface{}{{"{"}}o.{{$rel.LocalTable.ColumnNameGo}}}
{{end -}} {{end -}}
if boil.DebugMode { if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, query) fmt.Fprintln(boil.DebugWriter, query)
@ -113,11 +107,11 @@ func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) Set{{$rel.Function
} }
{{if .ToJoinTable -}} {{if .ToJoinTable -}}
remove{{$rel.LocalTable.NameGo}}From{{$rel.ForeignTable.NameGo}}Slice({{$rel.Function.Receiver}}, related) remove{{$rel.LocalTable.NameGo}}From{{$rel.ForeignTable.NameGo}}Slice(o, related)
{{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} = nil o.R.{{$rel.Function.Name}} = nil
{{else -}} {{else -}}
if {{$rel.Function.Receiver}}.R != nil { if o.R != nil {
for _, rel := range {{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} { for _, rel := range o.R.{{$rel.Function.Name}} {
rel.{{$rel.ForeignTable.ColumnNameGo}}.Valid = false rel.{{$rel.ForeignTable.ColumnNameGo}}.Valid = false
if rel.R == nil { if rel.R == nil {
continue continue
@ -126,24 +120,24 @@ func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) Set{{$rel.Function
rel.R.{{$rel.Function.ForeignName}} = nil rel.R.{{$rel.Function.ForeignName}} = nil
} }
{{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} = nil o.R.{{$rel.Function.Name}} = nil
} }
{{end -}} {{end -}}
return {{$rel.Function.Receiver}}.Add{{$rel.Function.Name}}(exec, insert, related...) return o.Add{{$rel.Function.Name}}(exec, insert, related...)
} }
// Remove{{$rel.Function.Name}} relationships from objects passed in. // Remove{{$rel.Function.Name}} relationships from objects passed in.
// Removes related items from R.{{$rel.Function.Name}} (uses pointer comparison, removal does not keep order) // Removes related items from R.{{$rel.Function.Name}} (uses pointer comparison, removal does not keep order)
// Sets related.R.{{$rel.Function.ForeignName}}. // Sets related.R.{{$rel.Function.ForeignName}}.
func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) Remove{{$rel.Function.Name}}(exec boil.Executor, related ...*{{$rel.ForeignTable.NameGo}}) error { func (o *{{$rel.LocalTable.NameGo}}) Remove{{$rel.Function.Name}}(exec boil.Executor, related ...*{{$rel.ForeignTable.NameGo}}) error {
var err error var err error
{{if .ToJoinTable -}} {{if .ToJoinTable -}}
query := fmt.Sprintf( 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)", "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), 1, 1),
) )
values := []interface{}{{"{"}}{{$rel.Function.Receiver}}.{{$rel.LocalTable.ColumnNameGo}}} values := []interface{}{{"{"}}o.{{$rel.LocalTable.ColumnNameGo}}}
if boil.DebugMode { if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, query) fmt.Fprintln(boil.DebugWriter, query)
@ -169,23 +163,23 @@ func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) Remove{{$rel.Funct
{{end -}} {{end -}}
{{if .ToJoinTable -}} {{if .ToJoinTable -}}
remove{{$rel.LocalTable.NameGo}}From{{$rel.ForeignTable.NameGo}}Slice({{$rel.Function.Receiver}}, related) remove{{$rel.LocalTable.NameGo}}From{{$rel.ForeignTable.NameGo}}Slice(o, related)
{{end -}} {{end -}}
if {{$rel.Function.Receiver}}.R == nil { if o.R == nil {
return nil return nil
} }
for _, rel := range related { for _, rel := range related {
for i, ri := range {{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} { for i, ri := range o.R.{{$rel.Function.Name}} {
if rel != ri { if rel != ri {
continue continue
} }
ln := len({{$rel.Function.Receiver}}.R.{{$rel.Function.Name}}) ln := len(o.R.{{$rel.Function.Name}})
if ln > 1 && i < ln-1 { if ln > 1 && i < ln-1 {
{{$rel.Function.Receiver}}.R.{{$rel.Function.Name}}[i] = {{$rel.Function.Receiver}}.R.{{$rel.Function.Name}}[ln-1] o.R.{{$rel.Function.Name}}[i] = o.R.{{$rel.Function.Name}}[ln-1]
} }
{{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} = {{$rel.Function.Receiver}}.R.{{$rel.Function.Name}}[:ln-1] o.R.{{$rel.Function.Name}} = o.R.{{$rel.Function.Name}}[:ln-1]
break break
} }
} }
@ -194,13 +188,17 @@ func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) Remove{{$rel.Funct
} }
{{if .ToJoinTable -}} {{if .ToJoinTable -}}
func remove{{$rel.LocalTable.NameGo}}From{{$rel.ForeignTable.NameGo}}Slice({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}, related []*{{$rel.ForeignTable.NameGo}}) { func remove{{$rel.LocalTable.NameGo}}From{{$rel.ForeignTable.NameGo}}Slice(o *{{$rel.LocalTable.NameGo}}, related []*{{$rel.ForeignTable.NameGo}}) {
for _, rel := range related { for _, rel := range related {
if rel.R == nil { if rel.R == nil {
continue continue
} }
for i, ri := range rel.R.{{$rel.Function.ForeignName}} { for i, ri := range rel.R.{{$rel.Function.ForeignName}} {
if {{$rel.Function.Receiver}}.{{$rel.Function.LocalAssignment}} != ri.{{$rel.Function.LocalAssignment}} { {{if $rel.Function.UsesBytes -}}
if 0 != bytes.Compare(o.{{$rel.Function.LocalAssignment}}, ri.{{$rel.Function.LocalAssignment}}) {
{{else -}}
if o.{{$rel.Function.LocalAssignment}} != ri.{{$rel.Function.LocalAssignment}} {
{{end -}}
continue continue
} }
@ -215,6 +213,5 @@ func remove{{$rel.LocalTable.NameGo}}From{{$rel.ForeignTable.NameGo}}Slice({{$re
} }
{{end -}}{{- /* if ToJoinTable */ -}} {{end -}}{{- /* if ToJoinTable */ -}}
{{- end -}}{{- /* if nullable foreign key */ -}} {{- end -}}{{- /* if nullable foreign key */ -}}
{{- end -}}{{- /* if unique foreign key */ -}}
{{- end -}}{{- /* range relationships */ -}} {{- end -}}{{- /* range relationships */ -}}
{{- end -}}{{- /* if IsJoinTable */ -}} {{- end -}}{{- /* if IsJoinTable */ -}}

View file

@ -1,4 +1,3 @@
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
{{- $tableNamePlural := .Table.Name | plural | titleCase -}} {{- $tableNamePlural := .Table.Name | plural | titleCase -}}
{{- $varNameSingular := .Table.Name | singular | camelCase -}} {{- $varNameSingular := .Table.Name | singular | camelCase -}}
// {{$tableNamePlural}}G retrieves all records. // {{$tableNamePlural}}G retrieves all records.

View file

@ -1,5 +1,4 @@
{{- $tableNameSingular := .Table.Name | singular | titleCase -}} {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
{{- $dbName := singular .Table.Name -}}
{{- $varNameSingular := .Table.Name | singular | camelCase -}} {{- $varNameSingular := .Table.Name | singular | camelCase -}}
{{- $colDefs := sqlColDefinitions .Table.Columns .Table.PKey.Columns -}} {{- $colDefs := sqlColDefinitions .Table.Columns .Table.PKey.Columns -}}
{{- $pkNames := $colDefs.Names | stringMap .StringFuncs.camelCase -}} {{- $pkNames := $colDefs.Names | stringMap .StringFuncs.camelCase -}}

View file

@ -69,7 +69,7 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
if len(cache.retMapping) != 0 { if len(cache.retMapping) != 0 {
{{if .UseLastInsertID -}} {{if .UseLastInsertID -}}
cache.retQuery = fmt.Sprintf("SELECT %s 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, "{{.LQ}},{{.RQ}}"), 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, "{{.LQ}},{{.RQ}}")) cache.query += fmt.Sprintf(" RETURNING {{.LQ}}%s{{.RQ}}", strings.Join(returnColumns, "{{.LQ}},{{.RQ}}"))
{{end -}} {{end -}}
@ -101,20 +101,24 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
return ErrSyncFail return ErrSyncFail
} }
if lastID != 0 { {{- $colName := index .Table.PKey.Columns 0 -}}
{{- $colName := index .Table.PKey.Columns 0 -}} {{- $col := .Table.GetColumn $colName -}}
{{- $col := .Table.GetColumn $colName -}} {{- $colTitled := $colName | singular | titleCase}}
o.{{$colName | singular | titleCase}} = {{$col.Type}}(lastID) {{if eq 1 (len .Table.PKey.Columns)}}
identifierCols = []interface{}{lastID} {{$cnames := .Table.Columns | filterColumnsByDefault true | columnNames}}
} else { {{if setInclude $colName $cnames}}
identifierCols = []interface{}{ o.{{$colTitled}} = {{$col.Type}}(lastID)
{{range .Table.PKey.Columns -}} identifierCols = []interface{}{lastID}
o.{{. | singular | titleCase}}, {{end}}
{{end -}} {{else}}
} identifierCols = []interface{}{
{{range .Table.PKey.Columns -}}
o.{{. | singular | titleCase}},
{{end -}}
} }
{{end}}
if lastID != 0 && len(cache.retMapping) == 1 { if lastID == 0 || len(cache.retMapping) != 1 || cache.retMapping[0] == {{$varNameSingular}}Mapping["{{$colTitled}}"] {
if boil.DebugMode { if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, cache.retQuery) fmt.Fprintln(boil.DebugWriter, cache.retQuery)
fmt.Fprintln(boil.DebugWriter, identifierCols...) fmt.Fprintln(boil.DebugWriter, identifierCols...)

View file

@ -1,8 +1,5 @@
{{- $tableNameSingular := .Table.Name | singular | titleCase -}} {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
{{- $varNameSingular := .Table.Name | singular | camelCase -}} {{- $varNameSingular := .Table.Name | singular | camelCase -}}
{{- $colDefs := sqlColDefinitions .Table.Columns .Table.PKey.Columns -}}
{{- $pkNames := $colDefs.Names | stringMap .StringFuncs.camelCase -}}
{{- $pkArgs := joinSlices " " $pkNames $colDefs.Types | join ", " -}}
{{- $schemaTable := .Table.Name | .SchemaTable -}} {{- $schemaTable := .Table.Name | .SchemaTable -}}
// UpdateG a single {{$tableNameSingular}} record. See Update for // UpdateG a single {{$tableNameSingular}} record. See Update for
// whitelist behavior description. // whitelist behavior description.
@ -52,6 +49,9 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
if !cached { if !cached {
wl := strmangle.UpdateColumnSet({{$varNameSingular}}Columns, {{$varNameSingular}}PrimaryKeyColumns, whitelist) wl := strmangle.UpdateColumnSet({{$varNameSingular}}Columns, {{$varNameSingular}}PrimaryKeyColumns, whitelist)
if len(wl) == 0 {
return errors.New("{{.PkgName}}: unable to update {{.Table.Name}}, could not build whitelist")
}
cache.query = fmt.Sprintf("UPDATE {{$schemaTable}} SET %s WHERE %s", cache.query = fmt.Sprintf("UPDATE {{$schemaTable}} SET %s WHERE %s",
strmangle.SetParamNames("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, wl), strmangle.SetParamNames("{{.LQ}}", "{{.RQ}}", {{if .Dialect.IndexPlaceholders}}1{{else}}0{{end}}, wl),
@ -63,10 +63,6 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
} }
} }
if len(cache.valueMapping) == 0 {
return errors.New("{{.PkgName}}: unable to update {{.Table.Name}}, could not build whitelist")
}
values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping) values := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), cache.valueMapping)
if boil.DebugMode { if boil.DebugMode {
@ -74,15 +70,11 @@ func (o *{{$tableNameSingular}}) Update(exec boil.Executor, whitelist ... string
fmt.Fprintln(boil.DebugWriter, values) fmt.Fprintln(boil.DebugWriter, values)
} }
result, err := exec.Exec(cache.query, values...) _, err = exec.Exec(cache.query, values...)
if err != nil { if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to update {{.Table.Name}} row") return errors.Wrap(err, "{{.PkgName}}: unable to update {{.Table.Name}} row")
} }
if r, err := result.RowsAffected(); err == nil && r != 1 {
return errors.Errorf("failed to update single row, updated %d rows", r)
}
if !cached { if !cached {
{{$varNameSingular}}UpdateCacheMut.Lock() {{$varNameSingular}}UpdateCacheMut.Lock()
{{$varNameSingular}}UpdateCache[key] = cache {{$varNameSingular}}UpdateCache[key] = cache
@ -156,7 +148,10 @@ func (o {{$tableNameSingular}}Slice) UpdateAll(exec boil.Executor, cols M) error
} }
// Append all of the primary key values for each column // Append all of the primary key values for each column
args = append(args, o.inPrimaryKeyArgs()...) for _, obj := range o {
pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), {{$varNameSingular}}PrimaryKeyMapping)
args = append(args, pkeyArgs...)
}
sql := fmt.Sprintf( sql := fmt.Sprintf(
"UPDATE {{$schemaTable}} SET %s WHERE ({{.LQ}}{{.Table.PKey.Columns | join (printf "%s,%s" .LQ .RQ)}}{{.RQ}}) IN (%s)", "UPDATE {{$schemaTable}} SET %s WHERE ({{.LQ}}{{.Table.PKey.Columns | join (printf "%s,%s" .LQ .RQ)}}{{.RQ}}) IN (%s)",
@ -169,14 +164,10 @@ func (o {{$tableNameSingular}}Slice) UpdateAll(exec boil.Executor, cols M) error
fmt.Fprintln(boil.DebugWriter, args...) fmt.Fprintln(boil.DebugWriter, args...)
} }
result, err := exec.Exec(sql, args...) _, err := exec.Exec(sql, args...)
if err != nil { if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to update all in {{$varNameSingular}} slice") return errors.Wrap(err, "{{.PkgName}}: unable to update all in {{$varNameSingular}} slice")
} }
if r, err := result.RowsAffected(); err == nil && r != ln {
return errors.Errorf("failed to update %d rows, only affected %d", ln, r)
}
return nil return nil
} }

View file

@ -35,6 +35,8 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if ne .DriverName
} }
{{- end}} {{- end}}
nzDefaults := queries.NonZeroDefaultSet({{$varNameSingular}}ColumnsWithDefault, o)
// Build cache key in-line uglily - mysql vs postgres problems // Build cache key in-line uglily - mysql vs postgres problems
buf := strmangle.GetBuffer() buf := strmangle.GetBuffer()
{{if ne .DriverName "mysql" -}} {{if ne .DriverName "mysql" -}}
@ -56,6 +58,10 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if ne .DriverName
for _, c := range whitelist { for _, c := range whitelist {
buf.WriteString(c) buf.WriteString(c)
} }
buf.WriteByte('.')
for _, c := range nzDefaults {
buf.WriteString(c)
}
key := buf.String() key := buf.String()
strmangle.PutBuffer(buf) strmangle.PutBuffer(buf)
@ -71,7 +77,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if ne .DriverName
{{$varNameSingular}}Columns, {{$varNameSingular}}Columns,
{{$varNameSingular}}ColumnsWithDefault, {{$varNameSingular}}ColumnsWithDefault,
{{$varNameSingular}}ColumnsWithoutDefault, {{$varNameSingular}}ColumnsWithoutDefault,
queries.NonZeroDefaultSet({{$varNameSingular}}ColumnsWithDefault, o), nzDefaults,
whitelist, whitelist,
) )
update := strmangle.UpdateColumnSet( update := strmangle.UpdateColumnSet(
@ -79,10 +85,13 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if ne .DriverName
{{$varNameSingular}}PrimaryKeyColumns, {{$varNameSingular}}PrimaryKeyColumns,
updateColumns, updateColumns,
) )
if len(update) == 0 {
return errors.New("{{.PkgName}}: unable to upsert {{.Table.Name}}, could not build update column list")
}
{{if ne .DriverName "mysql" -}} {{if ne .DriverName "mysql" -}}
var conflict []string conflict := conflictColumns
if len(conflictColumns) == 0 { if len(conflict) == 0 {
conflict = make([]string, len({{$varNameSingular}}PrimaryKeyColumns)) conflict = make([]string, len({{$varNameSingular}}PrimaryKeyColumns))
copy(conflict, {{$varNameSingular}}PrimaryKeyColumns) copy(conflict, {{$varNameSingular}}PrimaryKeyColumns)
} }
@ -125,34 +134,35 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if ne .DriverName
return errors.Wrap(err, "{{.PkgName}}: unable to upsert for {{.Table.Name}}") return errors.Wrap(err, "{{.PkgName}}: unable to upsert for {{.Table.Name}}")
} }
var lastID int64
var identifierCols []interface{}
if len(cache.retMapping) == 0 { if len(cache.retMapping) == 0 {
{{if not .NoHooks -}} goto CacheNoHooks
return o.doAfterUpsertHooks(exec)
{{else -}}
return nil
{{end -}}
} }
lastID, err := result.LastInsertId() lastID, err = result.LastInsertId()
if err != nil { if err != nil {
return ErrSyncFail return ErrSyncFail
} }
var identifierCols []interface{} {{- $colName := index .Table.PKey.Columns 0 -}}
if lastID != 0 { {{- $col := .Table.GetColumn $colName -}}
{{- $colName := index .Table.PKey.Columns 0 -}} {{- $colTitled := $colName | singular | titleCase}}
{{- $col := .Table.GetColumn $colName -}} {{if eq 1 (len .Table.PKey.Columns)}}
o.{{$colName | singular | titleCase}} = {{$col.Type}}(lastID) {{$cnames := .Table.Columns | filterColumnsByDefault true | columnNames}}
identifierCols = []interface{}{lastID} {{if setInclude $colName $cnames}}
} else { o.{{$colTitled}} = {{$col.Type}}(lastID)
identifierCols = []interface{}{ identifierCols = []interface{}{lastID}
{{range .Table.PKey.Columns -}} {{end}}
o.{{. | singular | titleCase}}, {{else}}
{{end -}} identifierCols = []interface{}{
} {{range .Table.PKey.Columns -}}
o.{{. | singular | titleCase}},
{{end -}}
} }
{{end}}
if lastID != 0 && len(cache.retMapping) == 1 { if lastID == 0 || len(cache.retMapping) != 1 || cache.retMapping[0] == {{$varNameSingular}}Mapping["{{$colTitled}}"] {
if boil.DebugMode { if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, cache.retQuery) fmt.Fprintln(boil.DebugWriter, cache.retQuery)
fmt.Fprintln(boil.DebugWriter, identifierCols...) fmt.Fprintln(boil.DebugWriter, identifierCols...)
@ -174,6 +184,9 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if ne .DriverName
} }
{{- end}} {{- end}}
{{if .UseLastInsertID -}}
CacheNoHooks:
{{end -}}
if !cached { if !cached {
{{$varNameSingular}}UpsertCacheMut.Lock() {{$varNameSingular}}UpsertCacheMut.Lock()
{{$varNameSingular}}UpsertCache[key] = cache {{$varNameSingular}}UpsertCache[key] = cache

View file

@ -42,8 +42,7 @@ func (o *{{$tableNameSingular}}) Delete(exec boil.Executor) error {
} }
{{- end}} {{- end}}
args := o.inPrimaryKeyArgs() args := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(o)), {{$varNameSingular}}PrimaryKeyMapping)
sql := "DELETE FROM {{$schemaTable}} WHERE {{if .Dialect.IndexPlaceholders}}{{whereClause .LQ .RQ 1 .Table.PKey.Columns}}{{else}}{{whereClause .LQ .RQ 0 .Table.PKey.Columns}}{{end}}" 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 { if boil.DebugMode {
@ -130,7 +129,11 @@ func (o {{$tableNameSingular}}Slice) DeleteAll(exec boil.Executor) error {
} }
{{- end}} {{- end}}
args := o.inPrimaryKeyArgs() var args []interface{}
for _, obj := range o {
pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), {{$varNameSingular}}PrimaryKeyMapping)
args = append(args, pkeyArgs...)
}
sql := fmt.Sprintf( sql := fmt.Sprintf(
"DELETE FROM {{$schemaTable}} WHERE (%s) IN (%s)", "DELETE FROM {{$schemaTable}} WHERE (%s) IN (%s)",

View file

@ -1,23 +0,0 @@
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
func (o {{$tableNameSingular}}) inPrimaryKeyArgs() []interface{} {
var args []interface{}
{{- range $key, $value := .Table.PKey.Columns }}
args = append(args, o.{{titleCase $value}})
{{ end -}}
return args
}
func (o {{$tableNameSingular}}Slice) inPrimaryKeyArgs() []interface{} {
var args []interface{}
for i := 0; i < len(o); i++ {
{{- range $key, $value := .Table.PKey.Columns }}
args = append(args, o[i].{{titleCase $value}})
{{ end -}}
}
return args
}

View file

@ -73,7 +73,11 @@ func (o *{{$tableNameSingular}}Slice) ReloadAll(exec boil.Executor) error {
} }
{{$varNamePlural}} := {{$tableNameSingular}}Slice{} {{$varNamePlural}} := {{$tableNameSingular}}Slice{}
args := o.inPrimaryKeyArgs() var args []interface{}
for _, obj := range *o {
pkeyArgs := queries.ValuesFromMapping(reflect.Indirect(reflect.ValueOf(obj)), {{$varNameSingular}}PrimaryKeyMapping)
args = append(args, pkeyArgs...)
}
sql := fmt.Sprintf( sql := fmt.Sprintf(
"SELECT {{$schemaTable}}.* FROM {{$schemaTable}} WHERE (%s) IN (%s)", "SELECT {{$schemaTable}}.* FROM {{$schemaTable}} WHERE (%s) IN (%s)",

View file

@ -23,7 +23,7 @@ func test{{$tableNamePlural}}Exists(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Unable to check if {{$tableNameSingular}} exists: %s", err) t.Errorf("Unable to check if {{$tableNameSingular}} exists: %s", err)
} }
if e != true { if !e {
t.Errorf("Expected {{$tableNameSingular}}ExistsG to return true, but got false.") t.Errorf("Expected {{$tableNameSingular}}ExistsG to return true, but got false.")
} }
} }

View file

@ -1,61 +0,0 @@
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
{{- $tableNamePlural := .Table.Name | plural | titleCase -}}
{{- $varNamePlural := .Table.Name | plural | camelCase -}}
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
var {{$varNameSingular}}DBTypes = map[string]string{{"{"}}{{.Table.Columns | columnDBTypes | makeStringMap}}{{"}"}}
func test{{$tableNamePlural}}InPrimaryKeyArgs(t *testing.T) {
t.Parallel()
var err error
var o {{$tableNameSingular}}
o = {{$tableNameSingular}}{}
seed := randomize.NewSeed()
if err = randomize.Struct(seed, &o, {{$varNameSingular}}DBTypes, true); err != nil {
t.Errorf("Could not randomize struct: %s", err)
}
args := o.inPrimaryKeyArgs()
if len(args) != len({{$varNameSingular}}PrimaryKeyColumns) {
t.Errorf("Expected args to be len %d, but got %d", len({{$varNameSingular}}PrimaryKeyColumns), len(args))
}
{{range $key, $value := .Table.PKey.Columns}}
if o.{{titleCase $value}} != args[{{$key}}] {
t.Errorf("Expected args[{{$key}}] to be value of o.{{titleCase $value}}, but got %#v", args[{{$key}}])
}
{{- end}}
}
func test{{$tableNamePlural}}SliceInPrimaryKeyArgs(t *testing.T) {
t.Parallel()
var err error
o := make({{$tableNameSingular}}Slice, 3)
seed := randomize.NewSeed()
for i := range o {
o[i] = &{{$tableNameSingular}}{}
if err = randomize.Struct(seed, o[i], {{$varNameSingular}}DBTypes, true); err != nil {
t.Errorf("Could not randomize struct: %s", err)
}
}
args := o.inPrimaryKeyArgs()
if len(args) != len({{$varNameSingular}}PrimaryKeyColumns) * 3 {
t.Errorf("Expected args to be len %d, but got %d", len({{$varNameSingular}}PrimaryKeyColumns) * 3, len(args))
}
argC := 0
for i := 0; i < 3; i++ {
{{range $key, $value := .Table.PKey.Columns}}
if o[i].{{titleCase $value}} != args[argC] {
t.Errorf("Expected args[%d] to be value of o.{{titleCase $value}}, but got %#v", i, args[i])
}
argC++
{{- end}}
}
}

View file

@ -1,4 +1,4 @@
{{- if eq .NoHooks false -}} {{- if not .NoHooks -}}
{{- $tableNameSingular := .Table.Name | singular | titleCase -}} {{- $tableNameSingular := .Table.Name | singular | titleCase -}}
{{- $tableNamePlural := .Table.Name | plural | titleCase -}} {{- $tableNamePlural := .Table.Name | plural | titleCase -}}
{{- $varNamePlural := .Table.Name | plural | camelCase -}} {{- $varNamePlural := .Table.Name | plural | camelCase -}}

View file

@ -0,0 +1,69 @@
{{- if .Table.IsJoinTable -}}
{{- else -}}
{{- $dot := . -}}
{{- range .Table.ToOneRelationships -}}
{{- $txt := txtsFromOneToOne $dot.Tables $dot.Table . -}}
{{- $varNameSingular := .Table | singular | camelCase -}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase -}}
func test{{$txt.LocalTable.NameGo}}OneToOne{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}(t *testing.T) {
tx := MustTx(boil.Begin())
defer tx.Rollback()
var foreign {{$txt.ForeignTable.NameGo}}
var local {{$txt.LocalTable.NameGo}}
seed := randomize.NewSeed()
if err := randomize.Struct(seed, &foreign, {{$foreignVarNameSingular}}DBTypes, true, {{$foreignVarNameSingular}}ColumnsWithDefault...); err != nil {
t.Errorf("Unable to randomize {{$txt.ForeignTable.NameGo}} struct: %s", err)
}
if err := randomize.Struct(seed, &local, {{$varNameSingular}}DBTypes, true, {{$varNameSingular}}ColumnsWithDefault...); err != nil {
t.Errorf("Unable to randomize {{$txt.LocalTable.NameGo}} struct: %s", err)
}
{{if .ForeignColumnNullable -}}
foreign.{{$txt.ForeignTable.ColumnNameGo}}.Valid = true
{{- end}}
{{if .Nullable -}}
local.{{$txt.LocalTable.ColumnNameGo}}.Valid = true
{{- end}}
if err := local.Insert(tx); err != nil {
t.Fatal(err)
}
foreign.{{$txt.Function.ForeignAssignment}} = local.{{$txt.Function.LocalAssignment}}
if err := foreign.Insert(tx); err != nil {
t.Fatal(err)
}
check, err := local.{{$txt.Function.Name}}(tx).One()
if err != nil {
t.Fatal(err)
}
{{if $txt.Function.UsesBytes -}}
if 0 != bytes.Compare(check.{{$txt.Function.ForeignAssignment}}, foreign.{{$txt.Function.ForeignAssignment}}) {
{{else -}}
if check.{{$txt.Function.ForeignAssignment}} != foreign.{{$txt.Function.ForeignAssignment}} {
{{end -}}
t.Errorf("want: %v, got %v", foreign.{{$txt.Function.ForeignAssignment}}, check.{{$txt.Function.ForeignAssignment}})
}
slice := {{$txt.LocalTable.NameGo}}Slice{&local}
if err = local.L.Load{{$txt.Function.Name}}(tx, false, &slice); err != nil {
t.Fatal(err)
}
if local.R.{{$txt.Function.Name}} == nil {
t.Error("struct should have been eager loaded")
}
local.R.{{$txt.Function.Name}} = nil
if err = local.L.Load{{$txt.Function.Name}}(tx, true, &local); err != nil {
t.Fatal(err)
}
if local.R.{{$txt.Function.Name}} == nil {
t.Error("struct should have been eager loaded")
}
}
{{end -}}{{/* range */}}
{{- end -}}{{/* join table */}}

View file

@ -0,0 +1,129 @@
{{- if .Table.IsJoinTable -}}
{{- else -}}
{{- $dot := . -}}
{{- range .Table.ToOneRelationships -}}
{{- $txt := txtsFromOneToOne $dot.Tables $dot.Table .}}
{{- $varNameSingular := .Table | singular | camelCase -}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase}}
func test{{$txt.LocalTable.NameGo}}OneToOneSetOp{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}(t *testing.T) {
var err error
tx := MustTx(boil.Begin())
defer tx.Rollback()
var a {{$txt.LocalTable.NameGo}}
var b, c {{$txt.ForeignTable.NameGo}}
seed := randomize.NewSeed()
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, strmangle.SetComplement({{$varNameSingular}}PrimaryKeyColumns, {{$varNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err)
}
if err = randomize.Struct(seed, &b, {{$foreignVarNameSingular}}DBTypes, false, strmangle.SetComplement({{$foreignVarNameSingular}}PrimaryKeyColumns, {{$foreignVarNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err)
}
if err = randomize.Struct(seed, &c, {{$foreignVarNameSingular}}DBTypes, false, strmangle.SetComplement({{$foreignVarNameSingular}}PrimaryKeyColumns, {{$foreignVarNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err)
}
if err := a.Insert(tx); err != nil {
t.Fatal(err)
}
if err = b.Insert(tx); err != nil {
t.Fatal(err)
}
for i, x := range []*{{$txt.ForeignTable.NameGo}}{&b, &c} {
err = a.Set{{$txt.Function.Name}}(tx, i != 0, x)
if err != nil {
t.Fatal(err)
}
if a.R.{{$txt.Function.Name}} != x {
t.Error("relationship struct not set to correct value")
}
if x.R.{{$txt.Function.ForeignName}} != &a {
t.Error("failed to append to foreign relationship struct")
}
{{if $txt.Function.UsesBytes -}}
if 0 != bytes.Compare(a.{{$txt.Function.LocalAssignment}}, x.{{$txt.Function.ForeignAssignment}}) {
{{else -}}
if a.{{$txt.Function.LocalAssignment}} != x.{{$txt.Function.ForeignAssignment}} {
{{end -}}
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}})
}
zero := reflect.Zero(reflect.TypeOf(x.{{$txt.Function.ForeignAssignment}}))
reflect.Indirect(reflect.ValueOf(&x.{{$txt.Function.ForeignAssignment}})).Set(zero)
if err = x.Reload(tx); err != nil {
t.Fatal("failed to reload", err)
}
{{if $txt.Function.UsesBytes -}}
if 0 != bytes.Compare(a.{{$txt.Function.LocalAssignment}}, x.{{$txt.Function.ForeignAssignment}}) {
{{else -}}
if a.{{$txt.Function.LocalAssignment}} != x.{{$txt.Function.ForeignAssignment}} {
{{end -}}
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}}, x.{{$txt.Function.ForeignAssignment}})
}
if err = x.Delete(tx); err != nil {
t.Fatal("failed to delete x", err)
}
}
}
{{- if .ForeignColumnNullable}}
func test{{$txt.LocalTable.NameGo}}OneToOneRemoveOp{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}(t *testing.T) {
var err error
tx := MustTx(boil.Begin())
defer tx.Rollback()
var a {{$txt.LocalTable.NameGo}}
var b {{$txt.ForeignTable.NameGo}}
seed := randomize.NewSeed()
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, strmangle.SetComplement({{$varNameSingular}}PrimaryKeyColumns, {{$varNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err)
}
if err = randomize.Struct(seed, &b, {{$foreignVarNameSingular}}DBTypes, false, strmangle.SetComplement({{$foreignVarNameSingular}}PrimaryKeyColumns, {{$foreignVarNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err)
}
if err = a.Insert(tx); err != nil {
t.Fatal(err)
}
if err = a.Set{{$txt.Function.Name}}(tx, true, &b); err != nil {
t.Fatal(err)
}
if err = a.Remove{{$txt.Function.Name}}(tx, &b); err != nil {
t.Error("failed to remove relationship")
}
count, err := a.{{$txt.Function.Name}}(tx).Count()
if err != nil {
t.Error(err)
}
if count != 0 {
t.Error("want no relationships remaining")
}
if a.R.{{$txt.Function.Name}} != nil {
t.Error("R struct entry should be nil")
}
if b.{{$txt.ForeignTable.ColumnNameGo}}.Valid {
t.Error("foreign key column should be nil")
}
if b.R.{{$txt.Function.ForeignName}} != nil {
t.Error("failed to remove a from b's relationships")
}
}
{{end -}}{{/* end if foreign key nullable */}}
{{- end -}}{{/* range */}}
{{- end -}}{{/* join table */}}

View file

@ -3,25 +3,27 @@
{{- $dot := . }} {{- $dot := . }}
{{- $table := .Table }} {{- $table := .Table }}
{{- range .Table.ToManyRelationships -}} {{- range .Table.ToManyRelationships -}}
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}} {{- $txt := txtsFromToMany $dot.Tables $table .}}
{{- template "relationship_to_one_test_helper" (textsFromOneToOneRelationship $dot.PkgName $dot.Tables $table .) -}} {{- $varNameSingular := .Table | singular | camelCase -}}
{{- else -}} func test{{$txt.LocalTable.NameGo}}ToMany{{$txt.Function.Name}}(t *testing.T) {
{{- $rel := textsFromRelationship $dot.Tables $table . -}}
func test{{$rel.LocalTable.NameGo}}ToMany{{$rel.Function.Name}}(t *testing.T) {
var err error var err error
tx := MustTx(boil.Begin()) tx := MustTx(boil.Begin())
defer tx.Rollback() defer tx.Rollback()
var a {{$rel.LocalTable.NameGo}} var a {{$txt.LocalTable.NameGo}}
var b, c {{$rel.ForeignTable.NameGo}} var b, c {{$txt.ForeignTable.NameGo}}
seed := randomize.NewSeed()
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, true, {{$varNameSingular}}ColumnsWithDefault...); err != nil {
t.Errorf("Unable to randomize {{$txt.LocalTable.NameGo}} struct: %s", err)
}
if err := a.Insert(tx); err != nil { if err := a.Insert(tx); err != nil {
t.Fatal(err) t.Fatal(err)
} }
seed := randomize.NewSeed() randomize.Struct(seed, &b, {{$txt.ForeignTable.NameSingular | camelCase}}DBTypes, false{{if not $txt.Function.UsesBytes}}, "{{.ForeignColumn}}"{{end}})
randomize.Struct(seed, &b, {{$rel.ForeignTable.NameSingular | camelCase}}DBTypes, false, "{{.ForeignColumn}}") randomize.Struct(seed, &c, {{$txt.ForeignTable.NameSingular | camelCase}}DBTypes, false{{if not $txt.Function.UsesBytes}}, "{{.ForeignColumn}}"{{end}})
randomize.Struct(seed, &c, {{$rel.ForeignTable.NameSingular | camelCase}}DBTypes, false, "{{.ForeignColumn}}")
{{if .Nullable -}} {{if .Nullable -}}
a.{{.Column | titleCase}}.Valid = true a.{{.Column | titleCase}}.Valid = true
{{- end}} {{- end}}
@ -30,8 +32,8 @@ func test{{$rel.LocalTable.NameGo}}ToMany{{$rel.Function.Name}}(t *testing.T) {
c.{{.ForeignColumn | titleCase}}.Valid = true c.{{.ForeignColumn | titleCase}}.Valid = true
{{- end}} {{- end}}
{{if not .ToJoinTable -}} {{if not .ToJoinTable -}}
b.{{$rel.Function.ForeignAssignment}} = a.{{$rel.Function.LocalAssignment}} b.{{$txt.Function.ForeignAssignment}} = a.{{$txt.Function.LocalAssignment}}
c.{{$rel.Function.ForeignAssignment}} = a.{{$rel.Function.LocalAssignment}} c.{{$txt.Function.ForeignAssignment}} = a.{{$txt.Function.LocalAssignment}}
{{- end}} {{- end}}
if err = b.Insert(tx); err != nil { if err = b.Insert(tx); err != nil {
t.Fatal(err) t.Fatal(err)
@ -41,30 +43,39 @@ func test{{$rel.LocalTable.NameGo}}ToMany{{$rel.Function.Name}}(t *testing.T) {
} }
{{if .ToJoinTable -}} {{if .ToJoinTable -}}
_, err = tx.Exec("insert into {{.JoinTable | $dot.SchemaTable}} ({{.JoinLocalColumn | $dot.Quotes}}, {{.JoinForeignColumn | $dot.Quotes}}) values {{if $dot.Dialect.IndexPlaceholders}}($1, $2){{else}}(?, ?){{end}}", a.{{$rel.LocalTable.ColumnNameGo}}, b.{{$rel.ForeignTable.ColumnNameGo}}) _, err = tx.Exec("insert into {{.JoinTable | $dot.SchemaTable}} ({{.JoinLocalColumn | $dot.Quotes}}, {{.JoinForeignColumn | $dot.Quotes}}) values {{if $dot.Dialect.IndexPlaceholders}}($1, $2){{else}}(?, ?){{end}}", a.{{$txt.LocalTable.ColumnNameGo}}, b.{{$txt.ForeignTable.ColumnNameGo}})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
_, err = tx.Exec("insert into {{.JoinTable | $dot.SchemaTable}} ({{.JoinLocalColumn | $dot.Quotes}}, {{.JoinForeignColumn | $dot.Quotes}}) values {{if $dot.Dialect.IndexPlaceholders}}($1, $2){{else}}(?, ?){{end}}", a.{{$rel.LocalTable.ColumnNameGo}}, c.{{$rel.ForeignTable.ColumnNameGo}}) _, err = tx.Exec("insert into {{.JoinTable | $dot.SchemaTable}} ({{.JoinLocalColumn | $dot.Quotes}}, {{.JoinForeignColumn | $dot.Quotes}}) values {{if $dot.Dialect.IndexPlaceholders}}($1, $2){{else}}(?, ?){{end}}", a.{{$txt.LocalTable.ColumnNameGo}}, c.{{$txt.ForeignTable.ColumnNameGo}})
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
{{end}} {{end}}
{{$varname := .ForeignTable | singular | camelCase -}} {{$varname := .ForeignTable | singular | camelCase -}}
{{$varname}}, err := a.{{$rel.Function.Name}}(tx).All() {{$varname}}, err := a.{{$txt.Function.Name}}(tx).All()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
bFound, cFound := false, false bFound, cFound := false, false
for _, v := range {{$varname}} { for _, v := range {{$varname}} {
if v.{{$rel.Function.ForeignAssignment}} == b.{{$rel.Function.ForeignAssignment}} { {{if $txt.Function.UsesBytes -}}
if 0 == bytes.Compare(v.{{$txt.Function.ForeignAssignment}}, b.{{$txt.Function.ForeignAssignment}}) {
bFound = true bFound = true
} }
if v.{{$rel.Function.ForeignAssignment}} == c.{{$rel.Function.ForeignAssignment}} { if 0 == bytes.Compare(v.{{$txt.Function.ForeignAssignment}}, c.{{$txt.Function.ForeignAssignment}}) {
cFound = true cFound = true
} }
{{else -}}
if v.{{$txt.Function.ForeignAssignment}} == b.{{$txt.Function.ForeignAssignment}} {
bFound = true
}
if v.{{$txt.Function.ForeignAssignment}} == c.{{$txt.Function.ForeignAssignment}} {
cFound = true
}
{{end -}}
} }
if !bFound { if !bFound {
@ -74,19 +85,19 @@ func test{{$rel.LocalTable.NameGo}}ToMany{{$rel.Function.Name}}(t *testing.T) {
t.Error("expected to find c") t.Error("expected to find c")
} }
slice := {{$rel.LocalTable.NameGo}}Slice{&a} slice := {{$txt.LocalTable.NameGo}}Slice{&a}
if err = a.L.Load{{$rel.Function.Name}}(tx, false, &slice); err != nil { if err = a.L.Load{{$txt.Function.Name}}(tx, false, &slice); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if got := len(a.R.{{$rel.Function.Name}}); got != 2 { if got := len(a.R.{{$txt.Function.Name}}); got != 2 {
t.Error("number of eager loaded records wrong, got:", got) t.Error("number of eager loaded records wrong, got:", got)
} }
a.R.{{$rel.Function.Name}} = nil a.R.{{$txt.Function.Name}} = nil
if err = a.L.Load{{$rel.Function.Name}}(tx, true, &a); err != nil { if err = a.L.Load{{$txt.Function.Name}}(tx, true, &a); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if got := len(a.R.{{$rel.Function.Name}}); got != 2 { if got := len(a.R.{{$txt.Function.Name}}); got != 2 {
t.Error("number of eager loaded records wrong, got:", got) t.Error("number of eager loaded records wrong, got:", got)
} }
@ -95,6 +106,5 @@ func test{{$rel.LocalTable.NameGo}}ToMany{{$rel.Function.Name}}(t *testing.T) {
} }
} }
{{end -}}{{- /* if unique */ -}} {{end -}}{{- /* range */ -}}
{{- end -}}{{- /* range */ -}}
{{- end -}}{{- /* outer if join table */ -}} {{- end -}}{{- /* outer if join table */ -}}

View file

@ -3,13 +3,9 @@
{{- $dot := . -}} {{- $dot := . -}}
{{- $table := .Table -}} {{- $table := .Table -}}
{{- range .Table.ToManyRelationships -}} {{- range .Table.ToManyRelationships -}}
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}} {{- $varNameSingular := .Table | singular | camelCase -}}
{{- template "relationship_to_one_setops_test_helper" (textsFromOneToOneRelationship $dot.PkgName $dot.Tables $table .) -}} {{- $foreignVarNameSingular := .ForeignTable | singular | camelCase -}}
{{- else -}} {{- $rel := txtsFromToMany $dot.Tables $table .}}
{{- $varNameSingular := .Table | singular | camelCase -}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase -}}
{{- $rel := textsFromRelationship $dot.Tables $table .}}
func test{{$rel.LocalTable.NameGo}}ToManyAddOp{{$rel.Function.Name}}(t *testing.T) { func test{{$rel.LocalTable.NameGo}}ToManyAddOp{{$rel.Function.Name}}(t *testing.T) {
var err error var err error
@ -20,12 +16,12 @@ func test{{$rel.LocalTable.NameGo}}ToManyAddOp{{$rel.Function.Name}}(t *testing.
var b, c, d, e {{$rel.ForeignTable.NameGo}} var b, c, d, e {{$rel.ForeignTable.NameGo}}
seed := randomize.NewSeed() seed := randomize.NewSeed()
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, {{$varNameSingular}}PrimaryKeyColumns...); err != nil { if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, strmangle.SetComplement({{$varNameSingular}}PrimaryKeyColumns, {{$varNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err) t.Fatal(err)
} }
foreigners := []*{{$rel.ForeignTable.NameGo}}{&b, &c, &d, &e} foreigners := []*{{$rel.ForeignTable.NameGo}}{&b, &c, &d, &e}
for _, x := range foreigners { for _, x := range foreigners {
if err = randomize.Struct(seed, x, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}PrimaryKeyColumns...); err != nil { if err = randomize.Struct(seed, x, {{$foreignVarNameSingular}}DBTypes, false, strmangle.SetComplement({{$foreignVarNameSingular}}PrimaryKeyColumns, {{$foreignVarNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
@ -63,12 +59,21 @@ func test{{$rel.LocalTable.NameGo}}ToManyAddOp{{$rel.Function.Name}}(t *testing.
} }
{{- else}} {{- else}}
{{if $rel.Function.UsesBytes -}}
if 0 != bytes.Compare(a.{{$rel.Function.LocalAssignment}}, first.{{$rel.Function.ForeignAssignment}}) {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, first.{{$rel.Function.ForeignAssignment}})
}
if 0 != bytes.Compare(a.{{$rel.Function.LocalAssignment}}, second.{{$rel.Function.ForeignAssignment}}) {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, second.{{$rel.Function.ForeignAssignment}})
}
{{else -}}
if a.{{$rel.Function.LocalAssignment}} != first.{{$rel.Function.ForeignAssignment}} { if a.{{$rel.Function.LocalAssignment}} != first.{{$rel.Function.ForeignAssignment}} {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, first.{{$rel.Function.ForeignAssignment}}) t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, first.{{$rel.Function.ForeignAssignment}})
} }
if a.{{$rel.Function.LocalAssignment}} != second.{{$rel.Function.ForeignAssignment}} { if a.{{$rel.Function.LocalAssignment}} != second.{{$rel.Function.ForeignAssignment}} {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, second.{{$rel.Function.ForeignAssignment}}) t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, second.{{$rel.Function.ForeignAssignment}})
} }
{{- end}}
if first.R.{{$rel.Function.ForeignName}} != &a { if first.R.{{$rel.Function.ForeignName}} != &a {
t.Error("relationship was not added properly to the foreign slice") t.Error("relationship was not added properly to the foreign slice")
@ -106,12 +111,12 @@ func test{{$rel.LocalTable.NameGo}}ToManySetOp{{$rel.Function.Name}}(t *testing.
var b, c, d, e {{$rel.ForeignTable.NameGo}} var b, c, d, e {{$rel.ForeignTable.NameGo}}
seed := randomize.NewSeed() seed := randomize.NewSeed()
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, {{$varNameSingular}}PrimaryKeyColumns...); err != nil { if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, strmangle.SetComplement({{$varNameSingular}}PrimaryKeyColumns, {{$varNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err) t.Fatal(err)
} }
foreigners := []*{{$rel.ForeignTable.NameGo}}{&b, &c, &d, &e} foreigners := []*{{$rel.ForeignTable.NameGo}}{&b, &c, &d, &e}
for _, x := range foreigners { for _, x := range foreigners {
if err = randomize.Struct(seed, x, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}PrimaryKeyColumns...); err != nil { if err = randomize.Struct(seed, x, {{$foreignVarNameSingular}}DBTypes, false, strmangle.SetComplement({{$foreignVarNameSingular}}PrimaryKeyColumns, {{$foreignVarNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
@ -174,12 +179,21 @@ func test{{$rel.LocalTable.NameGo}}ToManySetOp{{$rel.Function.Name}}(t *testing.
if c.{{$rel.ForeignTable.ColumnNameGo}}.Valid { if c.{{$rel.ForeignTable.ColumnNameGo}}.Valid {
t.Error("want c's foreign key value to be nil") t.Error("want c's foreign key value to be nil")
} }
{{if $rel.Function.UsesBytes -}}
if 0 != bytes.Compare(a.{{$rel.Function.LocalAssignment}}, d.{{$rel.Function.ForeignAssignment}}) {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, d.{{$rel.Function.ForeignAssignment}})
}
if 0 != bytes.Compare(a.{{$rel.Function.LocalAssignment}}, e.{{$rel.Function.ForeignAssignment}}) {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, e.{{$rel.Function.ForeignAssignment}})
}
{{else -}}
if a.{{$rel.Function.LocalAssignment}} != d.{{$rel.Function.ForeignAssignment}} { if a.{{$rel.Function.LocalAssignment}} != d.{{$rel.Function.ForeignAssignment}} {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, d.{{$rel.Function.ForeignAssignment}}) t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, d.{{$rel.Function.ForeignAssignment}})
} }
if a.{{$rel.Function.LocalAssignment}} != e.{{$rel.Function.ForeignAssignment}} { if a.{{$rel.Function.LocalAssignment}} != e.{{$rel.Function.ForeignAssignment}} {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, e.{{$rel.Function.ForeignAssignment}}) t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, e.{{$rel.Function.ForeignAssignment}})
} }
{{- end}}
if b.R.{{$rel.Function.ForeignName}} != nil { if b.R.{{$rel.Function.ForeignName}} != nil {
t.Error("relationship was not removed properly from the foreign struct") t.Error("relationship was not removed properly from the foreign struct")
@ -213,12 +227,12 @@ func test{{$rel.LocalTable.NameGo}}ToManyRemoveOp{{$rel.Function.Name}}(t *testi
var b, c, d, e {{$rel.ForeignTable.NameGo}} var b, c, d, e {{$rel.ForeignTable.NameGo}}
seed := randomize.NewSeed() seed := randomize.NewSeed()
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, {{$varNameSingular}}PrimaryKeyColumns...); err != nil { if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, strmangle.SetComplement({{$varNameSingular}}PrimaryKeyColumns, {{$varNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err) t.Fatal(err)
} }
foreigners := []*{{$rel.ForeignTable.NameGo}}{&b, &c, &d, &e} foreigners := []*{{$rel.ForeignTable.NameGo}}{&b, &c, &d, &e}
for _, x := range foreigners { for _, x := range foreigners {
if err = randomize.Struct(seed, x, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}PrimaryKeyColumns...); err != nil { if err = randomize.Struct(seed, x, {{$foreignVarNameSingular}}DBTypes, false, strmangle.SetComplement({{$foreignVarNameSingular}}PrimaryKeyColumns, {{$foreignVarNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
@ -303,6 +317,5 @@ func test{{$rel.LocalTable.NameGo}}ToManyRemoveOp{{$rel.Function.Name}}(t *testi
} }
} }
{{end -}} {{end -}}
{{- end -}}{{- /* if unique foreign key */ -}}
{{- end -}}{{- /* range relationships */ -}} {{- end -}}{{- /* range relationships */ -}}
{{- end -}}{{- /* outer if join table */ -}} {{- end -}}{{- /* outer if join table */ -}}

View file

@ -1,69 +1,69 @@
{{- define "relationship_to_one_test_helper"}}
func test{{.LocalTable.NameGo}}ToOne{{.ForeignTable.NameGo}}_{{.Function.Name}}(t *testing.T) {
tx := MustTx(boil.Begin())
defer tx.Rollback()
var foreign {{.ForeignTable.NameGo}}
var local {{.LocalTable.NameGo}}
{{if .ForeignKey.Nullable -}}
local.{{.ForeignKey.Column | titleCase}}.Valid = true
{{end}}
{{- if .ForeignKey.ForeignColumnNullable -}}
foreign.{{.ForeignKey.ForeignColumn | titleCase}}.Valid = true
{{end}}
{{if not .Function.OneToOne -}}
if err := foreign.Insert(tx); err != nil {
t.Fatal(err)
}
local.{{.Function.LocalAssignment}} = foreign.{{.Function.ForeignAssignment}}
if err := local.Insert(tx); err != nil {
t.Fatal(err)
}
{{else -}}
if err := local.Insert(tx); err != nil {
t.Fatal(err)
}
foreign.{{.Function.ForeignAssignment}} = local.{{.Function.LocalAssignment}}
if err := foreign.Insert(tx); err != nil {
t.Fatal(err)
}
{{end -}}
check, err := local.{{.Function.Name}}(tx).One()
if err != nil {
t.Fatal(err)
}
if check.{{.Function.ForeignAssignment}} != foreign.{{.Function.ForeignAssignment}} {
t.Errorf("want: %v, got %v", foreign.{{.Function.ForeignAssignment}}, check.{{.Function.ForeignAssignment}})
}
slice := {{.LocalTable.NameGo}}Slice{&local}
if err = local.L.Load{{.Function.Name}}(tx, false, &slice); err != nil {
t.Fatal(err)
}
if local.R.{{.Function.Name}} == nil {
t.Error("struct should have been eager loaded")
}
local.R.{{.Function.Name}} = nil
if err = local.L.Load{{.Function.Name}}(tx, true, &local); err != nil {
t.Fatal(err)
}
if local.R.{{.Function.Name}} == nil {
t.Error("struct should have been eager loaded")
}
}
{{end -}}
{{- if .Table.IsJoinTable -}} {{- if .Table.IsJoinTable -}}
{{- else -}} {{- else -}}
{{- $dot := . -}} {{- $dot := . -}}
{{- range .Table.FKeys -}} {{- range .Table.FKeys -}}
{{- $rel := textsFromForeignKey $dot.PkgName $dot.Tables $dot.Table . -}} {{- $txt := txtsFromFKey $dot.Tables $dot.Table . -}}
{{- template "relationship_to_one_test_helper" $rel -}} {{- $varNameSingular := .Table | singular | camelCase -}}
{{end -}} {{- $foreignVarNameSingular := .ForeignTable | singular | camelCase -}}
{{- end -}} func test{{$txt.LocalTable.NameGo}}ToOne{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}(t *testing.T) {
tx := MustTx(boil.Begin())
defer tx.Rollback()
var local {{$txt.LocalTable.NameGo}}
var foreign {{$txt.ForeignTable.NameGo}}
seed := randomize.NewSeed()
if err := randomize.Struct(seed, &local, {{$varNameSingular}}DBTypes, true, {{$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 {
t.Errorf("Unable to randomize {{$txt.ForeignTable.NameGo}} struct: %s", err)
}
{{if .Nullable -}}
local.{{$txt.LocalTable.ColumnNameGo}}.Valid = true
{{- end}}
{{if .ForeignColumnNullable -}}
foreign.{{$txt.ForeignTable.ColumnNameGo}}.Valid = true
{{- end}}
if err := foreign.Insert(tx); err != nil {
t.Fatal(err)
}
local.{{$txt.Function.LocalAssignment}} = foreign.{{$txt.Function.ForeignAssignment}}
if err := local.Insert(tx); err != nil {
t.Fatal(err)
}
check, err := local.{{$txt.Function.Name}}(tx).One()
if err != nil {
t.Fatal(err)
}
{{if $txt.Function.UsesBytes -}}
if 0 != bytes.Compare(check.{{$txt.Function.ForeignAssignment}}, foreign.{{$txt.Function.ForeignAssignment}}) {
{{else -}}
if check.{{$txt.Function.ForeignAssignment}} != foreign.{{$txt.Function.ForeignAssignment}} {
{{end -}}
t.Errorf("want: %v, got %v", foreign.{{$txt.Function.ForeignAssignment}}, check.{{$txt.Function.ForeignAssignment}})
}
slice := {{$txt.LocalTable.NameGo}}Slice{&local}
if err = local.L.Load{{$txt.Function.Name}}(tx, false, &slice); err != nil {
t.Fatal(err)
}
if local.R.{{$txt.Function.Name}} == nil {
t.Error("struct should have been eager loaded")
}
local.R.{{$txt.Function.Name}} = nil
if err = local.L.Load{{$txt.Function.Name}}(tx, true, &local); err != nil {
t.Fatal(err)
}
if local.R.{{$txt.Function.Name}} == nil {
t.Error("struct should have been eager loaded")
}
}
{{end -}}{{/* range */}}
{{- end -}}{{/* join table */}}

View file

@ -1,23 +1,27 @@
{{- define "relationship_to_one_setops_test_helper" -}} {{- if .Table.IsJoinTable -}}
{{- $varNameSingular := .ForeignKey.Table | singular | camelCase -}} {{- else -}}
{{- $foreignVarNameSingular := .ForeignKey.ForeignTable | singular | camelCase -}} {{- $dot := . -}}
func test{{.LocalTable.NameGo}}ToOneSetOp{{.ForeignTable.NameGo}}_{{.Function.Name}}(t *testing.T) { {{- range .Table.FKeys -}}
{{- $txt := txtsFromFKey $dot.Tables $dot.Table .}}
{{- $varNameSingular := .Table | singular | camelCase -}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase}}
func test{{$txt.LocalTable.NameGo}}ToOneSetOp{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}(t *testing.T) {
var err error var err error
tx := MustTx(boil.Begin()) tx := MustTx(boil.Begin())
defer tx.Rollback() defer tx.Rollback()
var a {{.LocalTable.NameGo}} var a {{$txt.LocalTable.NameGo}}
var b, c {{.ForeignTable.NameGo}} var b, c {{$txt.ForeignTable.NameGo}}
seed := randomize.NewSeed() seed := randomize.NewSeed()
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, {{$varNameSingular}}PrimaryKeyColumns...); err != nil { if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, strmangle.SetComplement({{$varNameSingular}}PrimaryKeyColumns, {{$varNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err = randomize.Struct(seed, &b, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}PrimaryKeyColumns...); err != nil { if err = randomize.Struct(seed, &b, {{$foreignVarNameSingular}}DBTypes, false, strmangle.SetComplement({{$foreignVarNameSingular}}PrimaryKeyColumns, {{$foreignVarNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err = randomize.Struct(seed, &c, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}PrimaryKeyColumns...); err != nil { if err = randomize.Struct(seed, &c, {{$foreignVarNameSingular}}DBTypes, false, strmangle.SetComplement({{$foreignVarNameSingular}}PrimaryKeyColumns, {{$foreignVarNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -28,57 +32,66 @@ func test{{.LocalTable.NameGo}}ToOneSetOp{{.ForeignTable.NameGo}}_{{.Function.Na
t.Fatal(err) t.Fatal(err)
} }
for i, x := range []*{{.ForeignTable.NameGo}}{&b, &c} { for i, x := range []*{{$txt.ForeignTable.NameGo}}{&b, &c} {
err = a.Set{{.Function.Name}}(tx, i != 0, x) err = a.Set{{$txt.Function.Name}}(tx, i != 0, x)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if a.{{.Function.LocalAssignment}} != x.{{.Function.ForeignAssignment}} { if a.R.{{$txt.Function.Name}} != x {
t.Error("foreign key was wrong value", a.{{.Function.LocalAssignment}})
}
if a.R.{{.Function.Name}} != x {
t.Error("relationship struct not set to correct value") t.Error("relationship struct not set to correct value")
} }
zero := reflect.Zero(reflect.TypeOf(a.{{.Function.LocalAssignment}})) {{if .Unique -}}
reflect.Indirect(reflect.ValueOf(&a.{{.Function.LocalAssignment}})).Set(zero) if x.R.{{$txt.Function.ForeignName}} != &a {
t.Error("failed to append to foreign relationship struct")
}
{{else -}}
if x.R.{{$txt.Function.ForeignName}}[0] != &a {
t.Error("failed to append to foreign relationship struct")
}
{{end -}}
{{if $txt.Function.UsesBytes -}}
if 0 != bytes.Compare(a.{{$txt.Function.LocalAssignment}}, x.{{$txt.Function.ForeignAssignment}}) {
{{else -}}
if a.{{$txt.Function.LocalAssignment}} != x.{{$txt.Function.ForeignAssignment}} {
{{end -}}
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}})
}
zero := reflect.Zero(reflect.TypeOf(a.{{$txt.Function.LocalAssignment}}))
reflect.Indirect(reflect.ValueOf(&a.{{$txt.Function.LocalAssignment}})).Set(zero)
if err = a.Reload(tx); err != nil { if err = a.Reload(tx); err != nil {
t.Fatal("failed to reload", err) t.Fatal("failed to reload", err)
} }
if a.{{.Function.LocalAssignment}} != x.{{.Function.ForeignAssignment}} { {{if $txt.Function.UsesBytes -}}
t.Error("foreign key was wrong value", a.{{.Function.LocalAssignment}}, x.{{.Function.ForeignAssignment}}) if 0 != bytes.Compare(a.{{$txt.Function.LocalAssignment}}, x.{{$txt.Function.ForeignAssignment}}) {
}
{{if .ForeignKey.Unique -}}
if x.R.{{.Function.ForeignName}} != &a {
t.Error("failed to append to foreign relationship struct")
}
{{else -}} {{else -}}
if x.R.{{.Function.ForeignName}}[0] != &a { if a.{{$txt.Function.LocalAssignment}} != x.{{$txt.Function.ForeignAssignment}} {
t.Error("failed to append to foreign relationship struct")
}
{{end -}} {{end -}}
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}}, x.{{$txt.Function.ForeignAssignment}})
}
} }
} }
{{- if .ForeignKey.Nullable}} {{- if .Nullable}}
func test{{.LocalTable.NameGo}}ToOneRemoveOp{{.ForeignTable.NameGo}}_{{.Function.Name}}(t *testing.T) { func test{{$txt.LocalTable.NameGo}}ToOneRemoveOp{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}(t *testing.T) {
var err error var err error
tx := MustTx(boil.Begin()) tx := MustTx(boil.Begin())
defer tx.Rollback() defer tx.Rollback()
var a {{.LocalTable.NameGo}} var a {{$txt.LocalTable.NameGo}}
var b {{.ForeignTable.NameGo}} var b {{$txt.ForeignTable.NameGo}}
seed := randomize.NewSeed() seed := randomize.NewSeed()
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, {{$varNameSingular}}PrimaryKeyColumns...); err != nil { if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, strmangle.SetComplement({{$varNameSingular}}PrimaryKeyColumns, {{$varNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err = randomize.Struct(seed, &b, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}PrimaryKeyColumns...); err != nil { if err = randomize.Struct(seed, &b, {{$foreignVarNameSingular}}DBTypes, false, strmangle.SetComplement({{$foreignVarNameSingular}}PrimaryKeyColumns, {{$foreignVarNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -86,15 +99,15 @@ func test{{.LocalTable.NameGo}}ToOneRemoveOp{{.ForeignTable.NameGo}}_{{.Function
t.Fatal(err) t.Fatal(err)
} }
if err = a.Set{{.Function.Name}}(tx, true, &b); err != nil { if err = a.Set{{$txt.Function.Name}}(tx, true, &b); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err = a.Remove{{.Function.Name}}(tx, &b); err != nil { if err = a.Remove{{$txt.Function.Name}}(tx, &b); err != nil {
t.Error("failed to remove relationship") t.Error("failed to remove relationship")
} }
count, err := a.{{.Function.Name}}(tx).Count() count, err := a.{{$txt.Function.Name}}(tx).Count()
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -102,32 +115,24 @@ func test{{.LocalTable.NameGo}}ToOneRemoveOp{{.ForeignTable.NameGo}}_{{.Function
t.Error("want no relationships remaining") t.Error("want no relationships remaining")
} }
if a.R.{{.Function.Name}} != nil { if a.R.{{$txt.Function.Name}} != nil {
t.Error("R struct entry should be nil") t.Error("R struct entry should be nil")
} }
if a.{{.LocalTable.ColumnNameGo}}.Valid { if a.{{$txt.LocalTable.ColumnNameGo}}.Valid {
t.Error("R struct entry should be nil") t.Error("foreign key value should be nil")
} }
{{if .ForeignKey.Unique -}} {{if .Unique -}}
if b.R.{{.Function.ForeignName}} != nil { if b.R.{{$txt.Function.ForeignName}} != nil {
t.Error("failed to remove a from b's relationships") t.Error("failed to remove a from b's relationships")
} }
{{else -}} {{else -}}
if len(b.R.{{.Function.ForeignName}}) != 0 { if len(b.R.{{$txt.Function.ForeignName}}) != 0 {
t.Error("failed to remove a from b's relationships") t.Error("failed to remove a from b's relationships")
} }
{{end -}} {{- end}}
} }
{{end -}} {{end -}}{{/* end if foreign key nullable */}}
{{- end -}} {{- end -}}{{/* range */}}
{{- if .Table.IsJoinTable -}} {{- end -}}{{/* join table */}}
{{- else -}}
{{- $dot := . -}}
{{- range .Table.FKeys -}}
{{- $rel := textsFromForeignKey $dot.PkgName $dot.Tables $dot.Table .}}
{{template "relationship_to_one_setops_test_helper" $rel -}}
{{- end -}}
{{- end -}}

View file

@ -35,3 +35,4 @@ func (f *fKeyDestroyer) Read(b []byte) (int, error) {
return f.buf.Read(b) return f.buf.Read(b)
} }

View file

@ -1,3 +1,4 @@
{{- $dot := .}}
// This test suite runs each operation test in parallel. // This test suite runs each operation test in parallel.
// Example, if your database has 3 tables, the suite will run: // Example, if your database has 3 tables, the suite will run:
// table1, table2 and table3 Delete in parallel // table1, table2 and table3 Delete in parallel
@ -104,18 +105,7 @@ func TestCount(t *testing.T) {
{{- end -}} {{- end -}}
} }
func TestHelpers(t *testing.T) { {{if not .NoHooks -}}
{{- range $index, $table := .Tables}}
{{- if $table.IsJoinTable -}}
{{- else -}}
{{- $tableName := $table.Name | plural | titleCase -}}
t.Run("{{$tableName}}", test{{$tableName}}InPrimaryKeyArgs)
t.Run("{{$tableName}}", test{{$tableName}}SliceInPrimaryKeyArgs)
{{end -}}
{{- end -}}
}
{{if eq .NoHooks false -}}
func TestHooks(t *testing.T) { func TestHooks(t *testing.T) {
{{- range $index, $table := .Tables}} {{- range $index, $table := .Tables}}
{{- if $table.IsJoinTable -}} {{- if $table.IsJoinTable -}}
@ -141,35 +131,41 @@ func TestInsert(t *testing.T) {
// TestToOne tests cannot be run in parallel // TestToOne tests cannot be run in parallel
// or deadlocks can occur. // or deadlocks can occur.
func TestToOne(t *testing.T) { func TestToOne(t *testing.T) {
{{- $dot := . -}}
{{- range $index, $table := .Tables}} {{- range $index, $table := .Tables}}
{{- if $table.IsJoinTable -}} {{- if $table.IsJoinTable -}}
{{- else -}} {{- else -}}
{{- range $table.FKeys -}} {{- range $table.FKeys -}}
{{- $rel := textsFromForeignKey $dot.PkgName $dot.Tables $table . -}} {{- $txt := txtsFromFKey $dot.Tables $table . -}}
t.Run("{{$rel.LocalTable.NameGo}}To{{$rel.ForeignTable.NameGo}}_{{$rel.Function.Name}}", test{{$rel.LocalTable.NameGo}}ToOne{{$rel.ForeignTable.NameGo}}_{{$rel.Function.Name}}) t.Run("{{$txt.LocalTable.NameGo}}To{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}", test{{$txt.LocalTable.NameGo}}ToOne{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}})
{{end -}}{{- /* fkey range */ -}} {{end -}}{{- /* fkey range */ -}}
{{- end -}}{{- /* if join table */ -}} {{- end -}}{{- /* if join table */ -}}
{{- end -}}{{- /* tables range */ -}} {{- end -}}{{- /* tables range */ -}}
} }
// TestOneToOne tests cannot be run in parallel
// or deadlocks can occur.
func TestOneToOne(t *testing.T) {
{{- range $index, $table := .Tables}}
{{- if $table.IsJoinTable -}}
{{- else -}}
{{- range $table.ToOneRelationships -}}
{{- $txt := txtsFromOneToOne $dot.Tables $table . -}}
t.Run("{{$txt.LocalTable.NameGo}}To{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}", test{{$txt.LocalTable.NameGo}}OneToOne{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}})
{{end -}}{{- /* range */ -}}
{{- end -}}{{- /* outer if join table */ -}}
{{- end -}}{{- /* outer tables range */ -}}
}
// TestToMany tests cannot be run in parallel // TestToMany tests cannot be run in parallel
// or deadlocks can occur. // or deadlocks can occur.
func TestToMany(t *testing.T) { func TestToMany(t *testing.T) {
{{- $dot := .}}
{{- range $index, $table := .Tables}} {{- range $index, $table := .Tables}}
{{- $tableName := $table.Name | plural | titleCase -}}
{{- if $table.IsJoinTable -}} {{- if $table.IsJoinTable -}}
{{- else -}} {{- else -}}
{{- range $table.ToManyRelationships -}} {{- range $table.ToManyRelationships -}}
{{- $rel := textsFromRelationship $dot.Tables $table . -}} {{- $txt := txtsFromToMany $dot.Tables $table . -}}
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}} t.Run("{{$txt.LocalTable.NameGo}}To{{$txt.Function.Name}}", test{{$txt.LocalTable.NameGo}}ToMany{{$txt.Function.Name}})
{{- $oneToOne := textsFromOneToOneRelationship $dot.PkgName $dot.Tables $table . -}} {{end -}}{{- /* range */ -}}
t.Run("{{$oneToOne.LocalTable.NameGo}}OneToOne{{$oneToOne.ForeignTable.NameGo}}_{{$oneToOne.Function.Name}}", test{{$oneToOne.LocalTable.NameGo}}ToOne{{$oneToOne.ForeignTable.NameGo}}_{{$oneToOne.Function.Name}})
{{else -}}
t.Run("{{$rel.LocalTable.NameGo}}ToMany{{$rel.Function.Name}}", test{{$rel.LocalTable.NameGo}}ToMany{{$rel.Function.Name}})
{{end -}}{{- /* if unique */ -}}
{{- end -}}{{- /* range */ -}}
{{- end -}}{{- /* outer if join table */ -}} {{- end -}}{{- /* outer if join table */ -}}
{{- end -}}{{- /* outer tables range */ -}} {{- end -}}{{- /* outer tables range */ -}}
} }
@ -177,13 +173,12 @@ func TestToMany(t *testing.T) {
// TestToOneSet tests cannot be run in parallel // TestToOneSet tests cannot be run in parallel
// or deadlocks can occur. // or deadlocks can occur.
func TestToOneSet(t *testing.T) { func TestToOneSet(t *testing.T) {
{{- $dot := . -}}
{{- range $index, $table := .Tables}} {{- range $index, $table := .Tables}}
{{- if $table.IsJoinTable -}} {{- if $table.IsJoinTable -}}
{{- else -}} {{- else -}}
{{- range $table.FKeys -}} {{- range $table.FKeys -}}
{{- $rel := textsFromForeignKey $dot.PkgName $dot.Tables $table . -}} {{- $txt := txtsFromFKey $dot.Tables $table . -}}
t.Run("{{$rel.LocalTable.NameGo}}To{{$rel.ForeignTable.NameGo}}_{{$rel.Function.Name}}", test{{$rel.LocalTable.NameGo}}ToOneSetOp{{$rel.ForeignTable.NameGo}}_{{$rel.Function.Name}}) t.Run("{{$txt.LocalTable.NameGo}}To{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}", test{{$txt.LocalTable.NameGo}}ToOneSetOp{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}})
{{end -}}{{- /* fkey range */ -}} {{end -}}{{- /* fkey range */ -}}
{{- end -}}{{- /* if join table */ -}} {{- end -}}{{- /* if join table */ -}}
{{- end -}}{{- /* tables range */ -}} {{- end -}}{{- /* tables range */ -}}
@ -192,35 +187,59 @@ func TestToOneSet(t *testing.T) {
// TestToOneRemove tests cannot be run in parallel // TestToOneRemove tests cannot be run in parallel
// or deadlocks can occur. // or deadlocks can occur.
func TestToOneRemove(t *testing.T) { func TestToOneRemove(t *testing.T) {
{{- $dot := . -}}
{{- range $index, $table := .Tables}} {{- range $index, $table := .Tables}}
{{- if $table.IsJoinTable -}} {{- if $table.IsJoinTable -}}
{{- else -}} {{- else -}}
{{- range $table.FKeys -}} {{- range $table.FKeys -}}
{{- $rel := textsFromForeignKey $dot.PkgName $dot.Tables $table . -}} {{- $txt := txtsFromFKey $dot.Tables $table . -}}
{{- if $rel.ForeignKey.Nullable -}} {{- if $txt.ForeignKey.Nullable -}}
t.Run("{{$rel.LocalTable.NameGo}}To{{$rel.ForeignTable.NameGo}}_{{$rel.Function.Name}}", test{{$rel.LocalTable.NameGo}}ToOneRemoveOp{{$rel.ForeignTable.NameGo}}_{{$rel.Function.Name}}) t.Run("{{$txt.LocalTable.NameGo}}To{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}", test{{$txt.LocalTable.NameGo}}ToOneRemoveOp{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}})
{{end -}}{{- /* if foreign key nullable */ -}} {{end -}}{{- /* if foreign key nullable */ -}}
{{- end -}}{{- /* fkey range */ -}} {{- end -}}{{- /* fkey range */ -}}
{{- end -}}{{- /* if join table */ -}} {{- end -}}{{- /* if join table */ -}}
{{- end -}}{{- /* tables range */ -}} {{- end -}}{{- /* tables range */ -}}
} }
// TestOneToOneSet tests cannot be run in parallel
// or deadlocks can occur.
func TestOneToOneSet(t *testing.T) {
{{- range $index, $table := .Tables}}
{{- if $table.IsJoinTable -}}
{{- else -}}
{{- range $table.ToOneRelationships -}}
{{- $txt := txtsFromOneToOne $dot.Tables $table . -}}
t.Run("{{$txt.LocalTable.NameGo}}To{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}", test{{$txt.LocalTable.NameGo}}OneToOneSetOp{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}})
{{end -}}{{- /* range to one relationships */ -}}
{{- end -}}{{- /* outer if join table */ -}}
{{- end -}}{{- /* outer tables range */ -}}
}
// TestOneToOneRemove tests cannot be run in parallel
// or deadlocks can occur.
func TestOneToOneRemove(t *testing.T) {
{{- range $index, $table := .Tables}}
{{- if $table.IsJoinTable -}}
{{- else -}}
{{- range $table.ToOneRelationships -}}
{{- if .ForeignColumnNullable -}}
{{- $txt := txtsFromOneToOne $dot.Tables $table . -}}
t.Run("{{$txt.LocalTable.NameGo}}To{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}", test{{$txt.LocalTable.NameGo}}OneToOneRemoveOp{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}})
{{end -}}{{- /* if foreign column nullable */ -}}
{{- end -}}{{- /* range */ -}}
{{- end -}}{{- /* outer if join table */ -}}
{{- end -}}{{- /* outer tables range */ -}}
}
// TestToManyAdd tests cannot be run in parallel // TestToManyAdd tests cannot be run in parallel
// or deadlocks can occur. // or deadlocks can occur.
func TestToManyAdd(t *testing.T) { func TestToManyAdd(t *testing.T) {
{{- $dot := .}}
{{- range $index, $table := .Tables}} {{- range $index, $table := .Tables}}
{{- $tableName := $table.Name | plural | titleCase -}}
{{- if $table.IsJoinTable -}} {{- if $table.IsJoinTable -}}
{{- else -}} {{- else -}}
{{- range $table.ToManyRelationships -}} {{- range $table.ToManyRelationships -}}
{{- $rel := textsFromRelationship $dot.Tables $table . -}} {{- $txt := txtsFromToMany $dot.Tables $table . -}}
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}} t.Run("{{$txt.LocalTable.NameGo}}To{{$txt.Function.Name}}", test{{$txt.LocalTable.NameGo}}ToManyAddOp{{$txt.Function.Name}})
{{- else -}} {{end -}}{{- /* range */ -}}
t.Run("{{$rel.LocalTable.NameGo}}ToMany{{$rel.Function.Name}}", test{{$rel.LocalTable.NameGo}}ToManyAddOp{{$rel.Function.Name}})
{{end -}}{{- /* if unique */ -}}
{{- end -}}{{- /* range */ -}}
{{- end -}}{{- /* outer if join table */ -}} {{- end -}}{{- /* outer if join table */ -}}
{{- end -}}{{- /* outer tables range */ -}} {{- end -}}{{- /* outer tables range */ -}}
} }
@ -228,22 +247,15 @@ func TestToManyAdd(t *testing.T) {
// TestToManySet tests cannot be run in parallel // TestToManySet tests cannot be run in parallel
// or deadlocks can occur. // or deadlocks can occur.
func TestToManySet(t *testing.T) { func TestToManySet(t *testing.T) {
{{- $dot := .}}
{{- range $index, $table := .Tables}} {{- range $index, $table := .Tables}}
{{- $tableName := $table.Name | plural | titleCase -}}
{{- if $table.IsJoinTable -}} {{- if $table.IsJoinTable -}}
{{- else -}} {{- else -}}
{{- range $table.ToManyRelationships -}} {{- range $table.ToManyRelationships -}}
{{- if not .ForeignColumnNullable -}} {{- if not .ForeignColumnNullable -}}
{{- else -}} {{- else -}}
{{- $rel := textsFromRelationship $dot.Tables $table . -}} {{- $txt := txtsFromToMany $dot.Tables $table . -}}
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}} t.Run("{{$txt.LocalTable.NameGo}}To{{$txt.Function.Name}}", test{{$txt.LocalTable.NameGo}}ToManySetOp{{$txt.Function.Name}})
{{- $oneToOne := textsFromOneToOneRelationship $dot.PkgName $dot.Tables $table . -}} {{end -}}{{- /* if foreign column nullable */ -}}
t.Run("{{$oneToOne.LocalTable.NameGo}}OneToOne{{$oneToOne.ForeignTable.NameGo}}_{{$oneToOne.Function.Name}}", test{{$oneToOne.LocalTable.NameGo}}ToOneSetOp{{$oneToOne.ForeignTable.NameGo}}_{{$oneToOne.Function.Name}})
{{else -}}
t.Run("{{$rel.LocalTable.NameGo}}ToMany{{$rel.Function.Name}}", test{{$rel.LocalTable.NameGo}}ToManySetOp{{$rel.Function.Name}})
{{end -}}{{- /* if unique */ -}}
{{- end -}}{{- /* if foreign column nullable */ -}}
{{- end -}}{{- /* range */ -}} {{- end -}}{{- /* range */ -}}
{{- end -}}{{- /* outer if join table */ -}} {{- end -}}{{- /* outer if join table */ -}}
{{- end -}}{{- /* outer tables range */ -}} {{- end -}}{{- /* outer tables range */ -}}
@ -252,22 +264,15 @@ func TestToManySet(t *testing.T) {
// TestToManyRemove tests cannot be run in parallel // TestToManyRemove tests cannot be run in parallel
// or deadlocks can occur. // or deadlocks can occur.
func TestToManyRemove(t *testing.T) { func TestToManyRemove(t *testing.T) {
{{- $dot := .}}
{{- range $index, $table := .Tables}} {{- range $index, $table := .Tables}}
{{- $tableName := $table.Name | plural | titleCase -}}
{{- if $table.IsJoinTable -}} {{- if $table.IsJoinTable -}}
{{- else -}} {{- else -}}
{{- range $table.ToManyRelationships -}} {{- range $table.ToManyRelationships -}}
{{- if not .ForeignColumnNullable -}} {{- if not .ForeignColumnNullable -}}
{{- else -}} {{- else -}}
{{- $rel := textsFromRelationship $dot.Tables $table . -}} {{- $txt := txtsFromToMany $dot.Tables $table . -}}
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}} t.Run("{{$txt.LocalTable.NameGo}}To{{$txt.Function.Name}}", test{{$txt.LocalTable.NameGo}}ToManyRemoveOp{{$txt.Function.Name}})
{{- $oneToOne := textsFromOneToOneRelationship $dot.PkgName $dot.Tables $table . -}} {{end -}}{{- /* if foreign column nullable */ -}}
t.Run("{{$oneToOne.LocalTable.NameGo}}OneToOne{{$oneToOne.ForeignTable.NameGo}}_{{$oneToOne.Function.Name}}", test{{$oneToOne.LocalTable.NameGo}}ToOneRemoveOp{{$oneToOne.ForeignTable.NameGo}}_{{$oneToOne.Function.Name}})
{{else -}}
t.Run("{{$rel.LocalTable.NameGo}}ToMany{{$rel.Function.Name}}", test{{$rel.LocalTable.NameGo}}ToManyRemoveOp{{$rel.Function.Name}})
{{end -}}{{- /* if unique */ -}}
{{- end -}}{{- /* if foreign column nullable */ -}}
{{- end -}}{{- /* range */ -}} {{- end -}}{{- /* range */ -}}
{{- end -}}{{- /* outer if join table */ -}} {{- end -}}{{- /* outer if join table */ -}}
{{- end -}}{{- /* outer tables range */ -}} {{- end -}}{{- /* outer tables range */ -}}

5
templates_test/types.tpl Normal file
View file

@ -0,0 +1,5 @@
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
var (
{{$varNameSingular}}DBTypes = map[string]string{{"{"}}{{.Table.Columns | columnDBTypes | makeStringMap}}{{"}"}}
_ = bytes.MinRead
)

View file

@ -5,6 +5,10 @@
func test{{$tableNamePlural}}Update(t *testing.T) { func test{{$tableNamePlural}}Update(t *testing.T) {
t.Parallel() t.Parallel()
if len({{$varNameSingular}}Columns) == len({{$varNameSingular}}PrimaryKeyColumns) {
t.Skip("Skipping table with only primary key columns")
}
seed := randomize.NewSeed() seed := randomize.NewSeed()
var err error var err error
{{$varNameSingular}} := &{{$tableNameSingular}}{} {{$varNameSingular}} := &{{$tableNameSingular}}{}
@ -27,28 +31,22 @@ func test{{$tableNamePlural}}Update(t *testing.T) {
t.Error("want one record, got:", count) t.Error("want one record, got:", count)
} }
if err = randomize.Struct(seed, {{$varNameSingular}}, {{$varNameSingular}}DBTypes, true, {{$varNameSingular}}PrimaryKeyColumns...); err != nil { if err = randomize.Struct(seed, {{$varNameSingular}}, {{$varNameSingular}}DBTypes, true, {{$varNameSingular}}ColumnsWithDefault...); err != nil {
t.Errorf("Unable to randomize {{$tableNameSingular}} struct: %s", err) t.Errorf("Unable to randomize {{$tableNameSingular}} struct: %s", err)
} }
// If table only contains primary key columns, we need to pass if err = {{$varNameSingular}}.Update(tx); err != nil {
// them into a whitelist to get a valid test result, t.Error(err)
// otherwise the Update method will error because it will not be able to
// generate a whitelist (due to it excluding primary key columns).
if strmangle.StringSliceMatch({{$varNameSingular}}Columns, {{$varNameSingular}}PrimaryKeyColumns) {
if err = {{$varNameSingular}}.Update(tx, {{$varNameSingular}}PrimaryKeyColumns...); err != nil {
t.Error(err)
}
} else {
if err = {{$varNameSingular}}.Update(tx); err != nil {
t.Error(err)
}
} }
} }
func test{{$tableNamePlural}}SliceUpdateAll(t *testing.T) { func test{{$tableNamePlural}}SliceUpdateAll(t *testing.T) {
t.Parallel() t.Parallel()
if len({{$varNameSingular}}Columns) == len({{$varNameSingular}}PrimaryKeyColumns) {
t.Skip("Skipping table with only primary key columns")
}
seed := randomize.NewSeed() seed := randomize.NewSeed()
var err error var err error
{{$varNameSingular}} := &{{$tableNameSingular}}{} {{$varNameSingular}} := &{{$tableNameSingular}}{}

View file

@ -3,11 +3,12 @@
{{- $varNamePlural := .Table.Name | plural | camelCase -}} {{- $varNamePlural := .Table.Name | plural | camelCase -}}
{{- $varNameSingular := .Table.Name | singular | camelCase -}} {{- $varNameSingular := .Table.Name | singular | camelCase -}}
func test{{$tableNamePlural}}Upsert(t *testing.T) { func test{{$tableNamePlural}}Upsert(t *testing.T) {
{{if not (eq .DriverName "postgres") -}}
t.Skip("not implemented for {{.DriverName}}")
{{end -}}
t.Parallel() t.Parallel()
if len({{$varNameSingular}}Columns) == len({{$varNameSingular}}PrimaryKeyColumns) {
t.Skip("Skipping table with only primary key columns")
}
seed := randomize.NewSeed() seed := randomize.NewSeed()
var err error var err error
// Attempt the INSERT side of an UPSERT // Attempt the INSERT side of an UPSERT

287
testdata/mysql_test_schema.sql vendored Normal file
View file

@ -0,0 +1,287 @@
CREATE TABLE magic (
id int PRIMARY KEY NOT NULL AUTO_INCREMENT,
id_two int NOT NULL,
id_three int,
bool_zero bool,
bool_one bool NULL,
bool_two bool NOT NULL,
bool_three bool NULL DEFAULT FALSE,
bool_four bool NULL DEFAULT TRUE,
bool_five bool NOT NULL DEFAULT FALSE,
bool_six bool NOT NULL DEFAULT TRUE,
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(2,1),
float_three float(2,1),
float_four float(2,1) NULL,
float_five float(2,1) NOT NULL,
float_six float(2,1) NULL DEFAULT 1.1,
float_seven float(2,1) NOT NULL DEFAULT 1.1,
float_eight float(2,1) NULL DEFAULT 0.0,
float_nine float(2,1) NULL DEFAULT 0.0,
bytea_zero binary,
bytea_one binary NULL,
bytea_two binary NOT NULL,
bytea_three binary NOT NULL DEFAULT 'a',
bytea_four binary NULL DEFAULT 'b',
bytea_five binary(100) NOT NULL DEFAULT 'abcdefghabcdefghabcdefgh',
bytea_six binary(100) NULL DEFAULT 'hgfedcbahgfedcbahgfedcba',
bytea_seven binary NOT NULL DEFAULT '',
bytea_eight binary NOT NULL DEFAULT '',
time_zero timestamp,
time_one date,
time_two timestamp NULL DEFAULT NULL,
time_three timestamp NULL,
time_five timestamp NULL DEFAULT CURRENT_TIMESTAMP,
time_nine timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
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 primary key not null auto_increment,
aa json NULL,
bb json NOT NULL,
kk double precision NULL,
ll double precision NOT NULL,
mm tinyint NULL,
nn tinyint NOT NULL,
oo tinyint(1) NULL,
pp tinyint(1) NOT NULL,
qq smallint NULL,
rr smallint NOT NULL,
ss mediumint NULL,
tt mediumint NOT NULL,
uu bigint NULL,
vv bigint NOT NULL,
ww float NULL,
xx float NOT NULL,
yy double NULL,
zz double NOT NULL,
aaa double precision NULL,
bbb double precision NOT NULL,
ccc real NULL,
ddd real NOT NULL,
eee boolean NULL,
fff boolean NOT NULL,
ggg date NULL,
hhh date NOT NULL,
iii datetime NULL,
jjj datetime NOT NULL,
kkk timestamp NULL,
lll timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
mmm binary NULL,
nnn binary NOT NULL,
ooo varbinary(100) NULL,
ppp varbinary(100) NOT NULL,
qqq tinyblob NULL,
rrr tinyblob NOT NULL,
sss blob NULL,
ttt blob NOT NULL,
uuu mediumblob NULL,
vvv mediumblob NOT NULL,
www longblob NULL,
xxx longblob NOT NULL,
yyy varchar(100) NULL,
zzz varchar(100) NOT NULL,
aaaa char NULL,
bbbb char NOT NULL,
cccc text NULL,
dddd text NOT NULL
);
create table owner (
id int primary key not null auto_increment,
name varchar(255) not null
);
create table cats (
id int primary key not null auto_increment,
name varchar(255) not null,
owner_id int references owner (id)
);
create table toys (
id int primary key not null auto_increment,
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 null
);
create table elephants (
id binary primary key,
name binary not null,
tiger_id binary 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 null,
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)
);
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,
byte_airport_id binary,
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)
);

328
testdata/postgres_test_schema.sql vendored Normal file
View file

@ -0,0 +1,328 @@
CREATE TABLE magic (
id serial PRIMARY KEY NOT NULL,
id_two serial NOT NULL,
id_three serial,
bool_zero bool,
bool_one bool NULL,
bool_two bool NOT NULL,
bool_three bool NULL DEFAULT FALSE,
bool_four bool NULL DEFAULT TRUE,
bool_five bool NOT NULL DEFAULT FALSE,
bool_six bool NOT NULL DEFAULT TRUE,
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 decimal,
float_one numeric,
float_two numeric(2,1),
float_three numeric(2,1),
float_four numeric(2,1) NULL,
float_five numeric(2,1) NOT NULL,
float_six numeric(2,1) NULL DEFAULT 1.1,
float_seven numeric(2,1) NOT NULL DEFAULT 1.1,
float_eight numeric(2,1) NULL DEFAULT 0.0,
float_nine numeric(2,1) NULL DEFAULT 0.0,
bytea_zero bytea,
bytea_one bytea NULL,
bytea_two bytea NOT NULL,
bytea_three bytea NOT NULL DEFAULT 'a',
bytea_four bytea NULL DEFAULT 'b',
bytea_five bytea NOT NULL DEFAULT 'abcdefghabcdefghabcdefgh',
bytea_six bytea NULL DEFAULT 'hgfedcbahgfedcbahgfedcba',
bytea_seven bytea NOT NULL DEFAULT '',
bytea_eight bytea NOT NULL DEFAULT '',
time_zero timestamp,
time_one date,
time_two timestamp NULL DEFAULT NULL,
time_three timestamp NULL,
time_four timestamp NOT NULL,
time_five timestamp NULL DEFAULT '1999-01-08 04:05:06.789',
time_six timestamp NULL DEFAULT '1999-01-08 04:05:06.789 -8:00',
time_seven timestamp NULL DEFAULT 'January 8 04:05:06 1999 PST',
time_eight timestamp NOT NULL DEFAULT '1999-01-08 04:05:06.789',
time_nine timestamp NOT NULL DEFAULT '1999-01-08 04:05:06.789 -8:00',
time_ten timestamp NOT NULL DEFAULT 'January 8 04:05:06 1999 PST',
time_eleven date NULL,
time_twelve date NOT NULL,
time_thirteen date NULL DEFAULT '1999-01-08',
time_fourteen date NULL DEFAULT 'January 8, 1999',
time_fifteen date NULL DEFAULT '19990108',
time_sixteen date NOT NULL DEFAULT '1999-01-08',
time_seventeen date NOT NULL DEFAULT 'January 8, 1999',
time_eighteen date NOT NULL DEFAULT '19990108',
uuid_zero uuid,
uuid_one uuid NULL,
uuid_two uuid NULL DEFAULT NULL,
uuid_three uuid NOT NULL,
uuid_four uuid NULL DEFAULT '6ba7b810-9dad-11d1-80b4-00c04fd430c8',
uuid_five uuid NOT NULL DEFAULT '6ba7b810-9dad-11d1-80b4-00c04fd430c8',
strange_one integer DEFAULT '5'::integer,
strange_two varchar(1000) DEFAULT 5::varchar,
strange_three timestamp without time zone default (now() at time zone 'utc'),
strange_four timestamp with time zone default (now() at time zone 'utc'),
strange_five interval NOT NULL DEFAULT '21 days',
strange_six interval NULL DEFAULT '23 hours',
aa json NULL,
bb json NOT NULL,
cc jsonb NULL,
dd jsonb NOT NULL,
ee box NULL,
ff box NOT NULL,
gg cidr NULL,
hh cidr NOT NULL,
ii circle NULL,
jj circle NOT NULL,
kk double precision NULL,
ll double precision NOT NULL,
mm inet NULL,
nn inet NOT NULL,
oo line NULL,
pp line NOT NULL,
qq lseg NULL,
rr lseg NOT NULL,
ss macaddr NULL,
tt macaddr NOT NULL,
uu money NULL,
vv money NOT NULL,
ww path NULL,
xx path NOT NULL,
yy pg_lsn NULL,
zz pg_lsn NOT NULL,
aaa point NULL,
bbb point NOT NULL,
ccc polygon NULL,
ddd polygon NOT NULL,
eee tsquery NULL,
fff tsquery NOT NULL,
ggg tsvector NULL,
hhh tsvector NOT NULL,
iii txid_snapshot NULL,
jjj txid_snapshot NOT NULL,
kkk xml NULL,
lll xml NOT NULL
);
create table owner (
id serial primary key not null,
name varchar(255) not null
);
create table cats (
id serial primary key not null,
name varchar(255) not null,
owner_id int references owner (id)
);
create table toys (
id serial primary key not null,
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 uuid,
toy_id uuid,
primary key (dragon_id, toy_id)
);
create table spider_toys (
spider_id uuid,
name character varying,
primary key (spider_id)
);
create table pals (
pal character varying,
name character varying,
primary key (pal)
);
create table friend (
friend character varying,
name character varying,
primary key (friend)
);
create table bro (
bros character varying,
name character varying,
primary key (bros)
);
create table enemies (
enemies character varying,
name character varying,
primary key (enemies)
);
create table chocolate (
dog varchar(100) primary key
);
create table waffles (
cat varchar(100) primary key
);
create table fun_arrays (
id serial,
fun_one integer[] null,
fun_two integer[] not null,
fun_three boolean[] null,
fun_four boolean[] not null,
fun_five varchar[] null,
fun_six varchar[] not null,
fun_seven decimal[] null,
fun_eight decimal[] not null,
fun_nine bytea[] null,
fun_ten bytea[] not null,
fun_eleven jsonb[] null,
fun_twelve jsonb[] not null,
fun_thirteen json[] null,
fun_fourteen json[] not null,
primary key (id)
);
create table tigers (
id bytea primary key,
name bytea null
);
create table elephants (
id bytea primary key,
name bytea not null,
tiger_id bytea null unique,
foreign key (tiger_id) references tigers (id)
);
create table wolves (
id bytea primary key,
name bytea not null,
tiger_id bytea not null unique,
foreign key (tiger_id) references tigers (id)
);
create table ants (
id bytea primary key,
name bytea not null,
tiger_id bytea not null,
foreign key (tiger_id) references tigers (id)
);
create table worms (
id bytea primary key,
name bytea not null,
tiger_id bytea null,
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,
name character varying
);
create table byte_airports (
id bytea primary key not null,
name character varying
);
create table byte_languages (
id bytea primary key not null,
name character varying
);
create table byte_jets (
id bytea primary key not null,
name character varying,
byte_pilot_id bytea unique,
byte_airport_id bytea,
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 bytea not null,
byte_language_id bytea 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)
);

View file

@ -1,215 +0,0 @@
CREATE TABLE magic (
id serial PRIMARY KEY NOT NULL,
id_two serial NOT NULL,
id_three serial,
bool_zero bool,
bool_one bool NULL,
bool_two bool NOT NULL,
bool_three bool NULL DEFAULT FALSE,
bool_four bool NULL DEFAULT TRUE,
bool_five bool NOT NULL DEFAULT FALSE,
bool_six bool NOT NULL DEFAULT TRUE,
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 decimal,
float_one numeric,
float_two numeric(2,1),
float_three numeric(2,1),
float_four numeric(2,1) NULL,
float_five numeric(2,1) NOT NULL,
float_six numeric(2,1) NULL DEFAULT 1.1,
float_seven numeric(2,1) NOT NULL DEFAULT 1.1,
float_eight numeric(2,1) NULL DEFAULT 0.0,
float_nine numeric(2,1) NULL DEFAULT 0.0,
bytea_zero bytea,
bytea_one bytea NULL,
bytea_two bytea NOT NULL,
bytea_three bytea NOT NULL DEFAULT 'a',
bytea_four bytea NULL DEFAULT 'b',
bytea_five bytea NOT NULL DEFAULT 'abcdefghabcdefghabcdefgh',
bytea_six bytea NULL DEFAULT 'hgfedcbahgfedcbahgfedcba',
bytea_seven bytea NOT NULL DEFAULT '',
bytea_eight bytea NOT NULL DEFAULT '',
time_zero timestamp,
time_one date,
time_two timestamp NULL DEFAULT NULL,
time_three timestamp NULL,
time_four timestamp NOT NULL,
time_five timestamp NULL DEFAULT '1999-01-08 04:05:06.789',
time_six timestamp NULL DEFAULT '1999-01-08 04:05:06.789 -8:00',
time_seven timestamp NULL DEFAULT 'January 8 04:05:06 1999 PST',
time_eight timestamp NOT NULL DEFAULT '1999-01-08 04:05:06.789',
time_nine timestamp NOT NULL DEFAULT '1999-01-08 04:05:06.789 -8:00',
time_ten timestamp NOT NULL DEFAULT 'January 8 04:05:06 1999 PST',
time_eleven date NULL,
time_twelve date NOT NULL,
time_thirteen date NULL DEFAULT '1999-01-08',
time_fourteen date NULL DEFAULT 'January 8, 1999',
time_fifteen date NULL DEFAULT '19990108',
time_sixteen date NOT NULL DEFAULT '1999-01-08',
time_seventeen date NOT NULL DEFAULT 'January 8, 1999',
time_eighteen date NOT NULL DEFAULT '19990108',
uuid_zero uuid,
uuid_one uuid NULL,
uuid_two uuid NULL DEFAULT NULL,
uuid_three uuid NOT NULL,
uuid_four uuid NULL DEFAULT '6ba7b810-9dad-11d1-80b4-00c04fd430c8',
uuid_five uuid NOT NULL DEFAULT '6ba7b810-9dad-11d1-80b4-00c04fd430c8',
strange_one integer DEFAULT '5'::integer,
strange_two varchar(1000) DEFAULT 5::varchar,
strange_three timestamp without time zone default (now() at time zone 'utc'),
strange_four timestamp with time zone default (now() at time zone 'utc'),
strange_five interval NOT NULL DEFAULT '21 days',
strange_six interval NULL DEFAULT '23 hours',
aa json NULL,
bb json NOT NULL,
cc jsonb NULL,
dd jsonb NOT NULL,
ee box NULL,
ff box NOT NULL,
gg cidr NULL,
hh cidr NOT NULL,
ii circle NULL,
jj circle NOT NULL,
kk double precision NULL,
ll double precision NOT NULL,
mm inet NULL,
nn inet NOT NULL,
oo line NULL,
pp line NOT NULL,
qq lseg NULL,
rr lseg NOT NULL,
ss macaddr NULL,
tt macaddr NOT NULL,
uu money NULL,
vv money NOT NULL,
ww path NULL,
xx path NOT NULL,
yy pg_lsn NULL,
zz pg_lsn NOT NULL,
aaa point NULL,
bbb point NOT NULL,
ccc polygon NULL,
ddd polygon NOT NULL,
eee tsquery NULL,
fff tsquery NOT NULL,
ggg tsvector NULL,
hhh tsvector NOT NULL,
iii txid_snapshot NULL,
jjj txid_snapshot NOT NULL,
kkk xml NULL,
lll xml NOT NULL
);
create table owner (
id serial primary key not null,
name varchar(255) not null
);
create table cats (
id serial primary key not null,
name varchar(255) not null,
owner_id int references owner (id)
);
create table toys (
id serial primary key not null,
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 uuid,
toy_id uuid,
primary key (dragon_id, toy_id)
);
create table spider_toys (
spider_id uuid,
name character varying,
primary key (spider_id)
);
create table pals (
pal character varying,
primary key (pal)
);
create table friend (
friend character varying,
primary key (friend)
);
create table bro (
bros character varying,
primary key (bros)
);
create table enemies (
enemies character varying,
primary key (enemies)
);
create table fun_arrays (
id serial,
fun_one integer[] null,
fun_two integer[] not null,
fun_three boolean[] null,
fun_four boolean[] not null,
fun_five varchar[] null,
fun_six varchar[] not null,
fun_seven decimal[] null,
fun_eight decimal[] not null,
fun_nine bytea[] null,
fun_ten bytea[] not null,
fun_eleven jsonb[] null,
fun_twelve jsonb[] not null,
fun_thirteen json[] null,
fun_fourteen json[] not null,
primary key (id)
)

View file

@ -8,8 +8,9 @@ import (
"github.com/vattle/sqlboiler/strmangle" "github.com/vattle/sqlboiler/strmangle"
) )
// RelationshipToOneTexts contains text that will be used by templates. // TxtToOne contains text that will be used by templates for a one-to-many or
type RelationshipToOneTexts struct { // a one-to-one relationship.
type TxtToOne struct {
ForeignKey bdb.ForeignKey ForeignKey bdb.ForeignKey
LocalTable struct { LocalTable struct {
@ -20,48 +21,42 @@ type RelationshipToOneTexts struct {
ForeignTable struct { ForeignTable struct {
NameGo string NameGo string
NamePluralGo string NamePluralGo string
Name string
ColumnNameGo string ColumnNameGo string
ColumnName string ColumnName string
} }
Function struct { Function struct {
PackageName string
Name string Name string
ForeignName string ForeignName string
Varname string Varname string
Receiver string UsesBytes bool
OneToOne bool
LocalAssignment string LocalAssignment string
ForeignAssignment string ForeignAssignment string
} }
} }
func textsFromForeignKey(packageName string, tables []bdb.Table, table bdb.Table, fkey bdb.ForeignKey) RelationshipToOneTexts { func txtsFromFKey(tables []bdb.Table, table bdb.Table, fkey bdb.ForeignKey) TxtToOne {
r := RelationshipToOneTexts{} r := TxtToOne{}
r.ForeignKey = fkey r.ForeignKey = fkey
r.LocalTable.NameGo = strmangle.TitleCase(strmangle.Singular(table.Name)) r.LocalTable.NameGo = strmangle.TitleCase(strmangle.Singular(table.Name))
r.LocalTable.ColumnNameGo = strmangle.TitleCase(strmangle.Singular(fkey.Column)) r.LocalTable.ColumnNameGo = strmangle.TitleCase(strmangle.Singular(fkey.Column))
r.ForeignTable.Name = fkey.ForeignTable
r.ForeignTable.NameGo = strmangle.TitleCase(strmangle.Singular(fkey.ForeignTable)) r.ForeignTable.NameGo = strmangle.TitleCase(strmangle.Singular(fkey.ForeignTable))
r.ForeignTable.NamePluralGo = strmangle.TitleCase(strmangle.Plural(fkey.ForeignTable)) r.ForeignTable.NamePluralGo = strmangle.TitleCase(strmangle.Plural(fkey.ForeignTable))
r.ForeignTable.ColumnName = fkey.ForeignColumn r.ForeignTable.ColumnName = fkey.ForeignColumn
r.ForeignTable.ColumnNameGo = strmangle.TitleCase(strmangle.Singular(fkey.ForeignColumn)) r.ForeignTable.ColumnNameGo = strmangle.TitleCase(strmangle.Singular(fkey.ForeignColumn))
r.Function.PackageName = packageName r.Function.Name = strmangle.TitleCase(strmangle.Singular(trimSuffixes(fkey.Column)))
r.Function.Name = strmangle.TitleCase(strmangle.Singular(strings.TrimSuffix(fkey.Column, "_id")))
plurality := strmangle.Plural plurality := strmangle.Plural
if fkey.Unique { if fkey.Unique {
plurality = strmangle.Singular plurality = strmangle.Singular
} }
r.Function.ForeignName = mkFunctionName(strmangle.Singular(fkey.ForeignTable), strmangle.TitleCase(plurality(fkey.Table)), fkey.Column, false) r.Function.ForeignName = mkFunctionName(strmangle.Singular(fkey.ForeignTable), strmangle.TitleCase(plurality(fkey.Table)), fkey.Column, false)
r.Function.Varname = strmangle.CamelCase(strmangle.Singular(fkey.ForeignTable)) r.Function.Varname = strmangle.CamelCase(strmangle.Singular(fkey.ForeignTable))
r.Function.Receiver = strings.ToLower(table.Name[:1])
if fkey.Nullable { if fkey.Nullable {
col := table.GetColumn(fkey.Column) col := table.GetColumn(fkey.Column)
@ -70,40 +65,51 @@ func textsFromForeignKey(packageName string, tables []bdb.Table, table bdb.Table
r.Function.LocalAssignment = strmangle.TitleCase(fkey.Column) r.Function.LocalAssignment = strmangle.TitleCase(fkey.Column)
} }
foreignTable := bdb.GetTable(tables, fkey.ForeignTable)
foreignColumn := foreignTable.GetColumn(fkey.ForeignColumn)
if fkey.ForeignColumnNullable { if fkey.ForeignColumnNullable {
foreignTable := bdb.GetTable(tables, fkey.ForeignTable) r.Function.ForeignAssignment = fmt.Sprintf("%s.%s", strmangle.TitleCase(fkey.ForeignColumn), strings.TrimPrefix(foreignColumn.Type, "null."))
col := foreignTable.GetColumn(fkey.ForeignColumn)
r.Function.ForeignAssignment = fmt.Sprintf("%s.%s", strmangle.TitleCase(fkey.ForeignColumn), strings.TrimPrefix(col.Type, "null."))
} else { } else {
r.Function.ForeignAssignment = strmangle.TitleCase(fkey.ForeignColumn) r.Function.ForeignAssignment = strmangle.TitleCase(fkey.ForeignColumn)
} }
r.Function.UsesBytes = foreignColumn.Type == "[]byte"
return r return r
} }
func textsFromOneToOneRelationship(packageName string, tables []bdb.Table, table bdb.Table, toMany bdb.ToManyRelationship) RelationshipToOneTexts { func txtsFromOneToOne(tables []bdb.Table, table bdb.Table, oneToOne bdb.ToOneRelationship) TxtToOne {
fkey := bdb.ForeignKey{ fkey := bdb.ForeignKey{
Table: toMany.Table, Table: oneToOne.Table,
Name: "none", Name: "none",
Column: toMany.Column, Column: oneToOne.Column,
Nullable: toMany.Nullable, Nullable: oneToOne.Nullable,
Unique: toMany.Unique, Unique: oneToOne.Unique,
ForeignTable: toMany.ForeignTable, ForeignTable: oneToOne.ForeignTable,
ForeignColumn: toMany.ForeignColumn, ForeignColumn: oneToOne.ForeignColumn,
ForeignColumnNullable: toMany.ForeignColumnNullable, ForeignColumnNullable: oneToOne.ForeignColumnNullable,
ForeignColumnUnique: toMany.ForeignColumnUnique, ForeignColumnUnique: oneToOne.ForeignColumnUnique,
} }
rel := textsFromForeignKey(packageName, tables, table, fkey) rel := txtsFromFKey(tables, table, fkey)
rel.Function.Name = strmangle.TitleCase(strmangle.Singular(toMany.ForeignTable)) col := table.GetColumn(oneToOne.Column)
rel.Function.ForeignName = mkFunctionName(strmangle.Singular(toMany.Table), strmangle.TitleCase(strmangle.Singular(toMany.Table)), toMany.ForeignColumn, false)
rel.Function.OneToOne = true // Reverse foreign key
rel.ForeignKey.Table, rel.ForeignKey.ForeignTable = rel.ForeignKey.ForeignTable, rel.ForeignKey.Table
rel.ForeignKey.Column, rel.ForeignKey.ForeignColumn = rel.ForeignKey.ForeignColumn, rel.ForeignKey.Column
rel.ForeignKey.Nullable, rel.ForeignKey.ForeignColumnNullable = rel.ForeignKey.ForeignColumnNullable, rel.ForeignKey.Nullable
rel.ForeignKey.Unique, rel.ForeignKey.ForeignColumnUnique = rel.ForeignKey.ForeignColumnUnique, rel.ForeignKey.Unique
rel.Function.Name = strmangle.TitleCase(strmangle.Singular(oneToOne.ForeignTable))
rel.Function.ForeignName = mkFunctionName(strmangle.Singular(oneToOne.Table), strmangle.TitleCase(strmangle.Singular(oneToOne.Table)), oneToOne.ForeignColumn, false)
rel.Function.UsesBytes = col.Type == "[]byte"
return rel return rel
} }
// RelationshipToManyTexts contains text that will be used by templates. // TxtToMany contains text that will be used by many-to-one relationships.
type RelationshipToManyTexts struct { type TxtToMany struct {
LocalTable struct { LocalTable struct {
NameGo string NameGo string
NameSingular string NameSingular string
@ -122,17 +128,18 @@ type RelationshipToManyTexts struct {
Function struct { Function struct {
Name string Name string
ForeignName string ForeignName string
Receiver string
UsesBytes bool
LocalAssignment string LocalAssignment string
ForeignAssignment string ForeignAssignment string
} }
} }
// textsFromRelationship creates a struct that does a lot of the text // txtsFromToMany creates a struct that does a lot of the text
// transformation in advance for a given relationship. // transformation in advance for a given relationship.
func textsFromRelationship(tables []bdb.Table, table bdb.Table, rel bdb.ToManyRelationship) RelationshipToManyTexts { func txtsFromToMany(tables []bdb.Table, table bdb.Table, rel bdb.ToManyRelationship) TxtToMany {
r := RelationshipToManyTexts{} r := TxtToMany{}
r.LocalTable.NameSingular = strmangle.Singular(table.Name) r.LocalTable.NameSingular = strmangle.Singular(table.Name)
r.LocalTable.NameGo = strmangle.TitleCase(r.LocalTable.NameSingular) r.LocalTable.NameGo = strmangle.TitleCase(r.LocalTable.NameSingular)
r.LocalTable.ColumnNameGo = strmangle.TitleCase(rel.Column) r.LocalTable.ColumnNameGo = strmangle.TitleCase(rel.Column)
@ -144,7 +151,6 @@ func textsFromRelationship(tables []bdb.Table, table bdb.Table, rel bdb.ToManyRe
r.ForeignTable.Slice = fmt.Sprintf("%sSlice", strmangle.TitleCase(r.ForeignTable.NameSingular)) r.ForeignTable.Slice = fmt.Sprintf("%sSlice", strmangle.TitleCase(r.ForeignTable.NameSingular))
r.ForeignTable.NameHumanReadable = strings.Replace(rel.ForeignTable, "_", " ", -1) r.ForeignTable.NameHumanReadable = strings.Replace(rel.ForeignTable, "_", " ", -1)
r.Function.Receiver = strings.ToLower(table.Name[:1])
r.Function.Name = mkFunctionName(r.LocalTable.NameSingular, r.ForeignTable.NamePluralGo, rel.ForeignColumn, rel.ToJoinTable) r.Function.Name = mkFunctionName(r.LocalTable.NameSingular, r.ForeignTable.NamePluralGo, rel.ForeignColumn, rel.ToJoinTable)
plurality := strmangle.Singular plurality := strmangle.Singular
foreignNamingColumn := rel.ForeignColumn foreignNamingColumn := rel.ForeignColumn
@ -152,10 +158,10 @@ func textsFromRelationship(tables []bdb.Table, table bdb.Table, rel bdb.ToManyRe
plurality = strmangle.Plural plurality = strmangle.Plural
foreignNamingColumn = rel.JoinLocalColumn foreignNamingColumn = rel.JoinLocalColumn
} }
r.Function.ForeignName = strmangle.TitleCase(plurality(strings.TrimSuffix(foreignNamingColumn, "_id"))) r.Function.ForeignName = strmangle.TitleCase(plurality(trimSuffixes(foreignNamingColumn)))
col := table.GetColumn(rel.Column)
if rel.Nullable { if rel.Nullable {
col := table.GetColumn(rel.Column)
r.Function.LocalAssignment = fmt.Sprintf("%s.%s", strmangle.TitleCase(rel.Column), strings.TrimPrefix(col.Type, "null.")) r.Function.LocalAssignment = fmt.Sprintf("%s.%s", strmangle.TitleCase(rel.Column), strings.TrimPrefix(col.Type, "null."))
} else { } else {
r.Function.LocalAssignment = strmangle.TitleCase(rel.Column) r.Function.LocalAssignment = strmangle.TitleCase(rel.Column)
@ -163,12 +169,14 @@ func textsFromRelationship(tables []bdb.Table, table bdb.Table, rel bdb.ToManyRe
if rel.ForeignColumnNullable { if rel.ForeignColumnNullable {
foreignTable := bdb.GetTable(tables, rel.ForeignTable) foreignTable := bdb.GetTable(tables, rel.ForeignTable)
col := foreignTable.GetColumn(rel.ForeignColumn) foreignColumn := foreignTable.GetColumn(rel.ForeignColumn)
r.Function.ForeignAssignment = fmt.Sprintf("%s.%s", strmangle.TitleCase(rel.ForeignColumn), strings.TrimPrefix(col.Type, "null.")) r.Function.ForeignAssignment = fmt.Sprintf("%s.%s", strmangle.TitleCase(rel.ForeignColumn), strings.TrimPrefix(foreignColumn.Type, "null."))
} else { } else {
r.Function.ForeignAssignment = strmangle.TitleCase(rel.ForeignColumn) r.Function.ForeignAssignment = strmangle.TitleCase(rel.ForeignColumn)
} }
r.Function.UsesBytes = col.Type == "[]byte"
return r return r
} }
@ -176,7 +184,7 @@ func textsFromRelationship(tables []bdb.Table, table bdb.Table, rel bdb.ToManyRe
// Simple case: yes - we can name the function the same as the plural table name // Simple case: yes - we can name the function the same as the plural table name
// Not simple case: We have to name the function based off the foreign key and the foreign table name // Not simple case: We have to name the function based off the foreign key and the foreign table name
func mkFunctionName(fkeyTableSingular, foreignTablePluralGo, fkeyColumn string, toJoinTable bool) string { func mkFunctionName(fkeyTableSingular, foreignTablePluralGo, fkeyColumn string, toJoinTable bool) string {
colName := strings.TrimSuffix(fkeyColumn, "_id") colName := trimSuffixes(fkeyColumn)
if toJoinTable || fkeyTableSingular == colName { if toJoinTable || fkeyTableSingular == colName {
return foreignTablePluralGo return foreignTablePluralGo
} }
@ -184,16 +192,17 @@ func mkFunctionName(fkeyTableSingular, foreignTablePluralGo, fkeyColumn string,
return strmangle.TitleCase(colName) + foreignTablePluralGo return strmangle.TitleCase(colName) + foreignTablePluralGo
} }
// PreserveDot allows us to pass in templateData to relationship templates var identifierSuffixes = []string{"_id", "_uuid", "_guid", "_oid"}
// called with the template function.
type PreserveDot struct {
Dot templateData
Rel RelationshipToOneTexts
}
func preserveDot(data templateData, obj RelationshipToOneTexts) PreserveDot { // trimSuffixes from the identifier
return PreserveDot{ func trimSuffixes(str string) string {
Dot: data, ln := len(str)
Rel: obj, for _, s := range identifierSuffixes {
str = strings.TrimSuffix(str, s)
if len(str) != ln {
break
}
} }
return str
} }

View file

@ -9,7 +9,7 @@ import (
"github.com/vattle/sqlboiler/bdb/drivers" "github.com/vattle/sqlboiler/bdb/drivers"
) )
func TestTextsFromForeignKey(t *testing.T) { func TestTxtsFromOne(t *testing.T) {
t.Parallel() t.Parallel()
tables, err := bdb.Tables(&drivers.MockDriver{}, "public", nil, nil) tables, err := bdb.Tables(&drivers.MockDriver{}, "public", nil, nil)
@ -18,26 +18,22 @@ func TestTextsFromForeignKey(t *testing.T) {
} }
jets := bdb.GetTable(tables, "jets") jets := bdb.GetTable(tables, "jets")
texts := textsFromForeignKey("models", tables, jets, jets.FKeys[0]) texts := txtsFromFKey(tables, jets, jets.FKeys[0])
expect := RelationshipToOneTexts{} expect := TxtToOne{}
expect.ForeignKey = jets.FKeys[0] expect.ForeignKey = jets.FKeys[0]
expect.LocalTable.NameGo = "Jet" expect.LocalTable.NameGo = "Jet"
expect.LocalTable.ColumnNameGo = "PilotID" expect.LocalTable.ColumnNameGo = "PilotID"
expect.ForeignTable.Name = "pilots"
expect.ForeignTable.NameGo = "Pilot" expect.ForeignTable.NameGo = "Pilot"
expect.ForeignTable.NamePluralGo = "Pilots" expect.ForeignTable.NamePluralGo = "Pilots"
expect.ForeignTable.ColumnName = "id" expect.ForeignTable.ColumnName = "id"
expect.ForeignTable.ColumnNameGo = "ID" expect.ForeignTable.ColumnNameGo = "ID"
expect.Function.PackageName = "models"
expect.Function.Name = "Pilot" expect.Function.Name = "Pilot"
expect.Function.ForeignName = "Jet" expect.Function.ForeignName = "Jet"
expect.Function.Varname = "pilot" expect.Function.Varname = "pilot"
expect.Function.Receiver = "j"
expect.Function.OneToOne = false
expect.Function.LocalAssignment = "PilotID.Int" expect.Function.LocalAssignment = "PilotID.Int"
expect.Function.ForeignAssignment = "ID" expect.Function.ForeignAssignment = "ID"
@ -46,25 +42,21 @@ func TestTextsFromForeignKey(t *testing.T) {
t.Errorf("Want:\n%s\nGot:\n%s\n", spew.Sdump(expect), spew.Sdump(texts)) t.Errorf("Want:\n%s\nGot:\n%s\n", spew.Sdump(expect), spew.Sdump(texts))
} }
texts = textsFromForeignKey("models", tables, jets, jets.FKeys[1]) texts = txtsFromFKey(tables, jets, jets.FKeys[1])
expect = RelationshipToOneTexts{} expect = TxtToOne{}
expect.ForeignKey = jets.FKeys[1] expect.ForeignKey = jets.FKeys[1]
expect.LocalTable.NameGo = "Jet" expect.LocalTable.NameGo = "Jet"
expect.LocalTable.ColumnNameGo = "AirportID" expect.LocalTable.ColumnNameGo = "AirportID"
expect.ForeignTable.Name = "airports"
expect.ForeignTable.NameGo = "Airport" expect.ForeignTable.NameGo = "Airport"
expect.ForeignTable.NamePluralGo = "Airports" expect.ForeignTable.NamePluralGo = "Airports"
expect.ForeignTable.ColumnName = "id" expect.ForeignTable.ColumnName = "id"
expect.ForeignTable.ColumnNameGo = "ID" expect.ForeignTable.ColumnNameGo = "ID"
expect.Function.PackageName = "models"
expect.Function.Name = "Airport" expect.Function.Name = "Airport"
expect.Function.ForeignName = "Jets" expect.Function.ForeignName = "Jets"
expect.Function.Varname = "airport" expect.Function.Varname = "airport"
expect.Function.Receiver = "j"
expect.Function.OneToOne = false
expect.Function.LocalAssignment = "AirportID" expect.Function.LocalAssignment = "AirportID"
expect.Function.ForeignAssignment = "ID" expect.Function.ForeignAssignment = "ID"
@ -78,7 +70,7 @@ func TestTextsFromForeignKey(t *testing.T) {
} }
} }
func TestTextsFromOneToOneRelationship(t *testing.T) { func TestTxtsFromOneToOne(t *testing.T) {
t.Parallel() t.Parallel()
tables, err := bdb.Tables(&drivers.MockDriver{}, "public", nil, nil) tables, err := bdb.Tables(&drivers.MockDriver{}, "public", nil, nil)
@ -87,37 +79,34 @@ func TestTextsFromOneToOneRelationship(t *testing.T) {
} }
pilots := bdb.GetTable(tables, "pilots") pilots := bdb.GetTable(tables, "pilots")
texts := textsFromOneToOneRelationship("models", tables, pilots, pilots.ToManyRelationships[0]) texts := txtsFromOneToOne(tables, pilots, pilots.ToOneRelationships[0])
expect := RelationshipToOneTexts{} expect := TxtToOne{}
expect.ForeignKey = bdb.ForeignKey{ expect.ForeignKey = bdb.ForeignKey{
Table: "pilots", Name: "none",
Name: "none",
Column: "id",
Nullable: false,
Unique: false,
ForeignTable: "jets", Table: "jets",
ForeignColumn: "pilot_id", Column: "pilot_id",
ForeignColumnNullable: true, Nullable: true,
ForeignColumnUnique: true, Unique: true,
ForeignTable: "pilots",
ForeignColumn: "id",
ForeignColumnNullable: false,
ForeignColumnUnique: false,
} }
expect.LocalTable.NameGo = "Pilot" expect.LocalTable.NameGo = "Pilot"
expect.LocalTable.ColumnNameGo = "ID" expect.LocalTable.ColumnNameGo = "ID"
expect.ForeignTable.Name = "jets"
expect.ForeignTable.NameGo = "Jet" expect.ForeignTable.NameGo = "Jet"
expect.ForeignTable.NamePluralGo = "Jets" expect.ForeignTable.NamePluralGo = "Jets"
expect.ForeignTable.ColumnName = "pilot_id" expect.ForeignTable.ColumnName = "pilot_id"
expect.ForeignTable.ColumnNameGo = "PilotID" expect.ForeignTable.ColumnNameGo = "PilotID"
expect.Function.PackageName = "models"
expect.Function.Name = "Jet" expect.Function.Name = "Jet"
expect.Function.ForeignName = "Pilot" expect.Function.ForeignName = "Pilot"
expect.Function.Varname = "jet" expect.Function.Varname = "jet"
expect.Function.Receiver = "p"
expect.Function.OneToOne = true
expect.Function.LocalAssignment = "ID" expect.Function.LocalAssignment = "ID"
expect.Function.ForeignAssignment = "PilotID.Int" expect.Function.ForeignAssignment = "PilotID.Int"
@ -127,7 +116,7 @@ func TestTextsFromOneToOneRelationship(t *testing.T) {
} }
} }
func TestTextsFromRelationship(t *testing.T) { func TestTxtsFromMany(t *testing.T) {
t.Parallel() t.Parallel()
tables, err := bdb.Tables(&drivers.MockDriver{}, "public", nil, nil) tables, err := bdb.Tables(&drivers.MockDriver{}, "public", nil, nil)
@ -136,31 +125,8 @@ func TestTextsFromRelationship(t *testing.T) {
} }
pilots := bdb.GetTable(tables, "pilots") pilots := bdb.GetTable(tables, "pilots")
texts := textsFromRelationship(tables, pilots, pilots.ToManyRelationships[0]) texts := txtsFromToMany(tables, pilots, pilots.ToManyRelationships[0])
expect := RelationshipToManyTexts{} expect := TxtToMany{}
expect.LocalTable.NameGo = "Pilot"
expect.LocalTable.NameSingular = "pilot"
expect.LocalTable.ColumnNameGo = "ID"
expect.ForeignTable.NameGo = "Jet"
expect.ForeignTable.NameSingular = "jet"
expect.ForeignTable.NamePluralGo = "Jets"
expect.ForeignTable.NameHumanReadable = "jets"
expect.ForeignTable.ColumnNameGo = "PilotID"
expect.ForeignTable.Slice = "JetSlice"
expect.Function.Name = "Jets"
expect.Function.ForeignName = "Pilot"
expect.Function.Receiver = "p"
expect.Function.LocalAssignment = "ID"
expect.Function.ForeignAssignment = "PilotID.Int"
if !reflect.DeepEqual(expect, texts) {
t.Errorf("Want:\n%s\nGot:\n%s\n", spew.Sdump(expect), spew.Sdump(texts))
}
texts = textsFromRelationship(tables, pilots, pilots.ToManyRelationships[1])
expect = RelationshipToManyTexts{}
expect.LocalTable.NameGo = "Pilot" expect.LocalTable.NameGo = "Pilot"
expect.LocalTable.NameSingular = "pilot" expect.LocalTable.NameSingular = "pilot"
expect.LocalTable.ColumnNameGo = "ID" expect.LocalTable.ColumnNameGo = "ID"
@ -174,7 +140,6 @@ func TestTextsFromRelationship(t *testing.T) {
expect.Function.Name = "Licenses" expect.Function.Name = "Licenses"
expect.Function.ForeignName = "Pilot" expect.Function.ForeignName = "Pilot"
expect.Function.Receiver = "p"
expect.Function.LocalAssignment = "ID" expect.Function.LocalAssignment = "ID"
expect.Function.ForeignAssignment = "PilotID" expect.Function.ForeignAssignment = "PilotID"
@ -182,8 +147,8 @@ func TestTextsFromRelationship(t *testing.T) {
t.Errorf("Want:\n%s\nGot:\n%s\n", spew.Sdump(expect), spew.Sdump(texts)) t.Errorf("Want:\n%s\nGot:\n%s\n", spew.Sdump(expect), spew.Sdump(texts))
} }
texts = textsFromRelationship(tables, pilots, pilots.ToManyRelationships[2]) texts = txtsFromToMany(tables, pilots, pilots.ToManyRelationships[1])
expect = RelationshipToManyTexts{} expect = TxtToMany{}
expect.LocalTable.NameGo = "Pilot" expect.LocalTable.NameGo = "Pilot"
expect.LocalTable.NameSingular = "pilot" expect.LocalTable.NameSingular = "pilot"
expect.LocalTable.ColumnNameGo = "ID" expect.LocalTable.ColumnNameGo = "ID"
@ -197,7 +162,6 @@ func TestTextsFromRelationship(t *testing.T) {
expect.Function.Name = "Languages" expect.Function.Name = "Languages"
expect.Function.ForeignName = "Pilots" expect.Function.ForeignName = "Pilots"
expect.Function.Receiver = "p"
expect.Function.LocalAssignment = "ID" expect.Function.LocalAssignment = "ID"
expect.Function.ForeignAssignment = "ID" expect.Function.ForeignAssignment = "ID"
@ -205,3 +169,15 @@ func TestTextsFromRelationship(t *testing.T) {
t.Errorf("Want:\n%s\nGot:\n%s\n", spew.Sdump(expect), spew.Sdump(texts)) t.Errorf("Want:\n%s\nGot:\n%s\n", spew.Sdump(expect), spew.Sdump(texts))
} }
} }
func TestTrimSuffixes(t *testing.T) {
t.Parallel()
for _, s := range identifierSuffixes {
a := "hello" + s
if z := trimSuffixes(a); z != "hello" {
t.Errorf("got %s", z)
}
}
}