Merge branch 'sets'
This commit is contained in:
commit
9553f462c7
20 changed files with 1104 additions and 136 deletions
|
@ -100,7 +100,7 @@ users, err := models.Users(db, Load("FavoriteMovies")).All()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Println(len(users.Loaded.FavoriteMovies))
|
fmt.Println(len(users.R.FavoriteMovies))
|
||||||
```
|
```
|
||||||
|
|
||||||
## How to boil your database
|
## How to boil your database
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (m *MockDriver) Columns(tableName string) ([]bdb.Column, error) {
|
||||||
func (m *MockDriver) ForeignKeyInfo(tableName string) ([]bdb.ForeignKey, error) {
|
func (m *MockDriver) ForeignKeyInfo(tableName string) ([]bdb.ForeignKey, error) {
|
||||||
return map[string][]bdb.ForeignKey{
|
return map[string][]bdb.ForeignKey{
|
||||||
"jets": {
|
"jets": {
|
||||||
{Table: "jets", Name: "jets_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id"},
|
{Table: "jets", Name: "jets_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", ForeignColumnUnique: true},
|
||||||
{Table: "jets", Name: "jets_airport_id_fk", Column: "airport_id", ForeignTable: "airports", ForeignColumn: "id"},
|
{Table: "jets", Name: "jets_airport_id_fk", Column: "airport_id", ForeignTable: "airports", ForeignColumn: "id"},
|
||||||
},
|
},
|
||||||
"licenses": {
|
"licenses": {
|
||||||
|
|
|
@ -1,98 +1,140 @@
|
||||||
package bdb
|
package bdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/vattle/sqlboiler/strmangle"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testInterface struct{}
|
type mockDriver struct{}
|
||||||
|
|
||||||
func (t testInterface) TableNames(exclude []string) ([]string, error) {
|
func (m mockDriver) TranslateColumnType(c Column) Column { return c }
|
||||||
return []string{"table1", "table2"}, nil
|
func (m mockDriver) UseLastInsertID() bool { return false }
|
||||||
|
func (m mockDriver) Open() error { return nil }
|
||||||
|
func (m mockDriver) Close() {}
|
||||||
|
|
||||||
|
func (m mockDriver) TableNames(exclude []string) ([]string, error) {
|
||||||
|
tables := []string{"pilots", "jets", "airports", "licenses", "hangars", "languages", "pilot_languages"}
|
||||||
|
return strmangle.SetComplement(tables, exclude), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var testCols = []Column{
|
// Columns returns a list of mock columns
|
||||||
{Name: "col1", Type: "character varying"},
|
func (m mockDriver) Columns(tableName string) ([]Column, error) {
|
||||||
{Name: "col2", Type: "character varying", Nullable: true},
|
return map[string][]Column{
|
||||||
}
|
"pilots": {
|
||||||
|
{Name: "id", Type: "int", DBType: "integer"},
|
||||||
func (t testInterface) Columns(tableName string) ([]Column, error) {
|
{Name: "name", Type: "string", DBType: "character"},
|
||||||
return testCols, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t testInterface) UseLastInsertID() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var testPkey = &PrimaryKey{Name: "pkey1", Columns: []string{"col1", "col2"}}
|
|
||||||
|
|
||||||
func (t testInterface) PrimaryKeyInfo(tableName string) (*PrimaryKey, error) {
|
|
||||||
return testPkey, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var testFkeys = []ForeignKey{
|
|
||||||
{
|
|
||||||
Name: "fkey1",
|
|
||||||
Column: "col1",
|
|
||||||
ForeignTable: "table2",
|
|
||||||
ForeignColumn: "col2",
|
|
||||||
},
|
},
|
||||||
{
|
"airports": {
|
||||||
Name: "fkey2",
|
{Name: "id", Type: "int", DBType: "integer"},
|
||||||
Column: "col2",
|
{Name: "size", Type: "null.Int", DBType: "integer", Nullable: true},
|
||||||
ForeignTable: "table1",
|
|
||||||
ForeignColumn: "col1",
|
|
||||||
},
|
},
|
||||||
|
"jets": {
|
||||||
|
{Name: "id", Type: "int", DBType: "integer"},
|
||||||
|
{Name: "pilot_id", Type: "int", DBType: "integer", Nullable: true, Unique: true},
|
||||||
|
{Name: "airport_id", Type: "int", DBType: "integer"},
|
||||||
|
{Name: "name", Type: "string", DBType: "character", Nullable: false},
|
||||||
|
{Name: "color", Type: "null.String", DBType: "character", Nullable: true},
|
||||||
|
{Name: "uuid", Type: "string", DBType: "uuid", Nullable: true},
|
||||||
|
{Name: "identifier", Type: "string", DBType: "uuid", Nullable: false},
|
||||||
|
{Name: "cargo", Type: "[]byte", DBType: "bytea", Nullable: false},
|
||||||
|
{Name: "manifest", Type: "[]byte", DBType: "bytea", Nullable: true, Unique: true},
|
||||||
|
},
|
||||||
|
"licenses": {
|
||||||
|
{Name: "id", Type: "int", DBType: "integer"},
|
||||||
|
{Name: "pilot_id", Type: "int", DBType: "integer"},
|
||||||
|
},
|
||||||
|
"hangars": {
|
||||||
|
{Name: "id", Type: "int", DBType: "integer"},
|
||||||
|
{Name: "name", Type: "string", DBType: "character", Nullable: true, Unique: true},
|
||||||
|
{Name: "hangar_id", Type: "int", DBType: "integer", Nullable: true},
|
||||||
|
},
|
||||||
|
"languages": {
|
||||||
|
{Name: "id", Type: "int", DBType: "integer"},
|
||||||
|
{Name: "language", Type: "string", DBType: "character", Nullable: false, Unique: true},
|
||||||
|
},
|
||||||
|
"pilot_languages": {
|
||||||
|
{Name: "pilot_id", Type: "int", DBType: "integer"},
|
||||||
|
{Name: "language_id", Type: "int", DBType: "integer"},
|
||||||
|
},
|
||||||
|
}[tableName], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t testInterface) ForeignKeyInfo(tableName string) ([]ForeignKey, error) {
|
// ForeignKeyInfo returns a list of mock foreignkeys
|
||||||
return testFkeys, nil
|
func (m mockDriver) ForeignKeyInfo(tableName string) ([]ForeignKey, error) {
|
||||||
|
return map[string][]ForeignKey{
|
||||||
|
"jets": {
|
||||||
|
{Table: "jets", Name: "jets_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", ForeignColumnUnique: true},
|
||||||
|
{Table: "jets", Name: "jets_airport_id_fk", Column: "airport_id", ForeignTable: "airports", ForeignColumn: "id"},
|
||||||
|
},
|
||||||
|
"licenses": {
|
||||||
|
{Table: "licenses", Name: "licenses_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id"},
|
||||||
|
},
|
||||||
|
"pilot_languages": {
|
||||||
|
{Table: "pilot_languages", Name: "pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id"},
|
||||||
|
{Table: "pilot_languages", Name: "jet_id_fk", Column: "language_id", ForeignTable: "languages", ForeignColumn: "id"},
|
||||||
|
},
|
||||||
|
"hangars": {
|
||||||
|
{Table: "hangars", Name: "hangar_fk_id", Column: "hangar_id", ForeignTable: "hangars", ForeignColumn: "id"},
|
||||||
|
},
|
||||||
|
}[tableName], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t testInterface) TranslateColumnType(column Column) Column {
|
// PrimaryKeyInfo returns mock primary key info for the passed in table name
|
||||||
column.Type = "string"
|
func (m mockDriver) PrimaryKeyInfo(tableName string) (*PrimaryKey, error) {
|
||||||
return column
|
return map[string]*PrimaryKey{
|
||||||
|
"pilots": {Name: "pilot_id_pkey", Columns: []string{"id"}},
|
||||||
|
"airports": {Name: "airport_id_pkey", Columns: []string{"id"}},
|
||||||
|
"jets": {Name: "jet_id_pkey", Columns: []string{"id"}},
|
||||||
|
"licenses": {Name: "license_id_pkey", Columns: []string{"id"}},
|
||||||
|
"hangars": {Name: "hangar_id_pkey", Columns: []string{"id"}},
|
||||||
|
"languages": {Name: "language_id_pkey", Columns: []string{"id"}},
|
||||||
|
"pilot_languages": {Name: "pilot_languages_pkey", Columns: []string{"pilot_id", "language_id"}},
|
||||||
|
}[tableName], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t testInterface) Open() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t testInterface) Close() {}
|
|
||||||
|
|
||||||
func TestTables(t *testing.T) {
|
func TestTables(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
tables, err := Tables(testInterface{})
|
tables, err := Tables(mockDriver{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tables) != 2 {
|
if len(tables) != 7 {
|
||||||
t.Errorf("Expected len 2, got: %d\n", len(tables))
|
t.Errorf("Expected len 7, got: %d\n", len(tables))
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(tables[0].Columns, testCols) {
|
pilots := GetTable(tables, "pilots")
|
||||||
t.Errorf("Did not get expected columns, got:\n%#v\n%#v", tables[0].Columns, testCols)
|
if len(pilots.Columns) != 2 {
|
||||||
|
t.Error()
|
||||||
|
}
|
||||||
|
if pilots.ToManyRelationships[0].ForeignTable != "jets" {
|
||||||
|
t.Error("want a to many to jets")
|
||||||
|
}
|
||||||
|
if pilots.ToManyRelationships[1].ForeignTable != "licenses" {
|
||||||
|
t.Error("want a to many to languages")
|
||||||
|
}
|
||||||
|
if pilots.ToManyRelationships[2].ForeignTable != "languages" {
|
||||||
|
t.Error("want a to many to languages")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !tables[0].IsJoinTable || !tables[1].IsJoinTable {
|
jets := GetTable(tables, "jets")
|
||||||
t.Errorf("Expected IsJoinTable to be true")
|
if len(jets.ToManyRelationships) != 0 {
|
||||||
|
t.Error("want no to many relationships")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(tables[0].PKey, testPkey) {
|
languages := GetTable(tables, "pilot_languages")
|
||||||
t.Errorf("Did not get expected PKey, got:\n#%v\n%#v", tables[0].PKey, testPkey)
|
if !languages.IsJoinTable {
|
||||||
|
t.Error("languages is a join table")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(tables[0].FKeys, testFkeys) {
|
hangars := GetTable(tables, "hangars")
|
||||||
t.Errorf("Did not get expected Fkey, got:\n%#v\n%#v", tables[0].FKeys, testFkeys)
|
if len(hangars.ToManyRelationships) != 1 || hangars.ToManyRelationships[0].ForeignTable != "hangars" {
|
||||||
|
t.Error("want 1 to many relationships")
|
||||||
}
|
}
|
||||||
|
if len(hangars.FKeys) != 1 || hangars.FKeys[0].ForeignTable != "hangars" {
|
||||||
if len(tables[0].ToManyRelationships) != 1 {
|
t.Error("want one hangar foreign key to itself")
|
||||||
t.Error("wanted a to many relationship")
|
|
||||||
}
|
|
||||||
if len(tables[1].ToManyRelationships) != 1 {
|
|
||||||
t.Error("wanted a to many relationship")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,10 +38,6 @@ func toManyRelationships(table Table, tables []Table) []ToManyRelationship {
|
||||||
var relationships []ToManyRelationship
|
var relationships []ToManyRelationship
|
||||||
|
|
||||||
for _, t := range tables {
|
for _, t := range tables {
|
||||||
if t.Name == table.Name {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range t.FKeys {
|
for _, f := range t.FKeys {
|
||||||
if f.ForeignTable != table.Name {
|
if f.ForeignTable != table.Name {
|
||||||
continue
|
continue
|
||||||
|
@ -58,7 +54,7 @@ func buildRelationship(localTable Table, foreignKey ForeignKey, foreignTable Tab
|
||||||
if !foreignTable.IsJoinTable {
|
if !foreignTable.IsJoinTable {
|
||||||
col := localTable.GetColumn(foreignKey.ForeignColumn)
|
col := localTable.GetColumn(foreignKey.ForeignColumn)
|
||||||
return ToManyRelationship{
|
return ToManyRelationship{
|
||||||
Table: foreignKey.Table,
|
Table: localTable.Name,
|
||||||
Column: foreignKey.ForeignColumn,
|
Column: foreignKey.ForeignColumn,
|
||||||
Nullable: col.Nullable,
|
Nullable: col.Nullable,
|
||||||
Unique: col.Unique,
|
Unique: col.Unique,
|
||||||
|
@ -72,7 +68,7 @@ func buildRelationship(localTable Table, foreignKey ForeignKey, foreignTable Tab
|
||||||
|
|
||||||
col := foreignTable.GetColumn(foreignKey.Column)
|
col := foreignTable.GetColumn(foreignKey.Column)
|
||||||
relationship := ToManyRelationship{
|
relationship := ToManyRelationship{
|
||||||
Table: foreignKey.Table,
|
Table: localTable.Name,
|
||||||
Column: foreignKey.ForeignColumn,
|
Column: foreignKey.ForeignColumn,
|
||||||
Nullable: col.Nullable,
|
Nullable: col.Nullable,
|
||||||
Unique: col.Unique,
|
Unique: col.Unique,
|
||||||
|
|
|
@ -77,6 +77,7 @@ func TestToManyRelationships(t *testing.T) {
|
||||||
|
|
||||||
expected := []ToManyRelationship{
|
expected := []ToManyRelationship{
|
||||||
{
|
{
|
||||||
|
Table: "pilots",
|
||||||
Column: "id",
|
Column: "id",
|
||||||
Nullable: false,
|
Nullable: false,
|
||||||
Unique: false,
|
Unique: false,
|
||||||
|
@ -89,6 +90,7 @@ func TestToManyRelationships(t *testing.T) {
|
||||||
ToJoinTable: false,
|
ToJoinTable: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Table: "pilots",
|
||||||
Column: "id",
|
Column: "id",
|
||||||
Nullable: false,
|
Nullable: false,
|
||||||
Unique: false,
|
Unique: false,
|
||||||
|
@ -101,6 +103,7 @@ func TestToManyRelationships(t *testing.T) {
|
||||||
ToJoinTable: false,
|
ToJoinTable: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Table: "pilots",
|
||||||
Column: "id",
|
Column: "id",
|
||||||
Nullable: false,
|
Nullable: false,
|
||||||
Unique: false,
|
Unique: false,
|
||||||
|
@ -209,6 +212,7 @@ func TestToManyRelationshipsNull(t *testing.T) {
|
||||||
|
|
||||||
expected := []ToManyRelationship{
|
expected := []ToManyRelationship{
|
||||||
{
|
{
|
||||||
|
Table: "pilots",
|
||||||
Column: "id",
|
Column: "id",
|
||||||
Nullable: true,
|
Nullable: true,
|
||||||
Unique: true,
|
Unique: true,
|
||||||
|
@ -221,6 +225,7 @@ func TestToManyRelationshipsNull(t *testing.T) {
|
||||||
ToJoinTable: false,
|
ToJoinTable: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Table: "pilots",
|
||||||
Column: "id",
|
Column: "id",
|
||||||
Nullable: true,
|
Nullable: true,
|
||||||
Unique: true,
|
Unique: true,
|
||||||
|
@ -233,6 +238,7 @@ func TestToManyRelationshipsNull(t *testing.T) {
|
||||||
ToJoinTable: false,
|
ToJoinTable: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Table: "pilots",
|
||||||
Column: "id",
|
Column: "id",
|
||||||
Nullable: true,
|
Nullable: true,
|
||||||
Unique: true,
|
Unique: true,
|
||||||
|
|
|
@ -110,7 +110,7 @@ func (q *Query) BindFast(obj interface{}, titleCases map[string]string) error {
|
||||||
// loadRelationships dynamically calls the template generated eager load
|
// loadRelationships dynamically calls the template generated eager load
|
||||||
// functions of the form:
|
// functions of the form:
|
||||||
//
|
//
|
||||||
// func (t *TableLoaded) LoadRelationshipName(exec Executor, singular bool, obj interface{})
|
// func (t *TableR) LoadRelationshipName(exec Executor, singular bool, obj interface{})
|
||||||
//
|
//
|
||||||
// The arguments to this function are:
|
// The arguments to this function are:
|
||||||
// - t is not considered here, and is always passed nil. The function exists on a loaded
|
// - t is not considered here, and is always passed nil. The function exists on a loaded
|
||||||
|
@ -125,11 +125,11 @@ func (q *Query) loadRelationships(obj interface{}, singular bool) error {
|
||||||
typ = typ.Elem().Elem()
|
typ = typ.Elem().Elem()
|
||||||
}
|
}
|
||||||
|
|
||||||
rel, found := typ.FieldByName("Loaded")
|
rel, found := typ.FieldByName("R")
|
||||||
// If the users object has no loaded struct, it must be
|
// If the users object has no loaded struct, it must be
|
||||||
// a custom object and we should not attempt to load any relationships.
|
// a custom object and we should not attempt to load any relationships.
|
||||||
if !found {
|
if !found {
|
||||||
return errors.New("load query mod was used but bound struct contained no Loaded field")
|
return errors.New("load query mod was used but bound struct contained no R field")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, relationship := range q.load {
|
for _, relationship := range q.load {
|
||||||
|
|
|
@ -166,9 +166,9 @@ func TestBindSingular(t *testing.T) {
|
||||||
|
|
||||||
var loadFunctionCalled bool
|
var loadFunctionCalled bool
|
||||||
|
|
||||||
type testLoadedStruct struct{}
|
type testRStruct struct{}
|
||||||
|
|
||||||
func (r *testLoadedStruct) LoadTestOne(exec Executor, singular bool, obj interface{}) error {
|
func (r *testRStruct) LoadTestOne(exec Executor, singular bool, obj interface{}) error {
|
||||||
loadFunctionCalled = true
|
loadFunctionCalled = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -179,7 +179,7 @@ func TestLoadRelationshipsSlice(t *testing.T) {
|
||||||
|
|
||||||
testSlice := []*struct {
|
testSlice := []*struct {
|
||||||
ID int
|
ID int
|
||||||
Loaded *testLoadedStruct
|
R *testRStruct
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
q := Query{load: []string{"TestOne"}, executor: nil}
|
q := Query{load: []string{"TestOne"}, executor: nil}
|
||||||
|
@ -198,7 +198,7 @@ func TestLoadRelationshipsSingular(t *testing.T) {
|
||||||
|
|
||||||
testSingular := struct {
|
testSingular := struct {
|
||||||
ID int
|
ID int
|
||||||
Loaded *testLoadedStruct
|
R *testRStruct
|
||||||
}{}
|
}{}
|
||||||
|
|
||||||
q := Query{load: []string{"TestOne"}, executor: nil}
|
q := Query{load: []string{"TestOne"}, executor: nil}
|
||||||
|
|
|
@ -11,15 +11,15 @@ type {{$modelName}} struct {
|
||||||
{{end -}}
|
{{end -}}
|
||||||
{{- if .Table.IsJoinTable -}}
|
{{- if .Table.IsJoinTable -}}
|
||||||
{{- else}}
|
{{- else}}
|
||||||
Loaded *{{$modelName}}Loaded `boil:"-" json:"-" toml:"-" yaml:"-"`
|
R *{{$modelName}}R `boil:"-" json:"-" toml:"-" yaml:"-"`
|
||||||
{{end -}}
|
{{end -}}
|
||||||
}
|
}
|
||||||
|
|
||||||
{{- $dot := . -}}
|
{{- $dot := . -}}
|
||||||
{{- if .Table.IsJoinTable -}}
|
{{- if .Table.IsJoinTable -}}
|
||||||
{{- else}}
|
{{- else}}
|
||||||
// {{$modelName}}Loaded are where relationships are eagerly loaded.
|
// {{$modelName}}R is where relationships are stored.
|
||||||
type {{$modelName}}Loaded struct {
|
type {{$modelName}}R struct {
|
||||||
{{range .Table.FKeys -}}
|
{{range .Table.FKeys -}}
|
||||||
{{- $rel := textsFromForeignKey $dot.PkgName $dot.Tables $dot.Table . -}}
|
{{- $rel := textsFromForeignKey $dot.PkgName $dot.Tables $dot.Table . -}}
|
||||||
{{- template "relationship_to_one_struct_helper" $rel}}
|
{{- template "relationship_to_one_struct_helper" $rel}}
|
||||||
|
|
|
@ -28,11 +28,11 @@ func ({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}) {{$rel.Function.Na
|
||||||
{{if .ToJoinTable -}}
|
{{if .ToJoinTable -}}
|
||||||
queryMods = append(queryMods,
|
queryMods = append(queryMods,
|
||||||
qm.InnerJoin(`"{{.JoinTable}}" as "{{id 1}}" on "{{id 0}}"."{{.ForeignColumn}}" = "{{id 1}}"."{{.JoinForeignColumn}}"`),
|
qm.InnerJoin(`"{{.JoinTable}}" as "{{id 1}}" on "{{id 0}}"."{{.ForeignColumn}}" = "{{id 1}}"."{{.JoinForeignColumn}}"`),
|
||||||
qm.Where(`"{{id 1}}"."{{.JoinLocalColumn}}"=$1`, {{.Column | titleCase | printf "%s.%s" $rel.Function.Receiver }}),
|
qm.Where(`"{{id 1}}"."{{.JoinLocalColumn}}"=$1`, {{$rel.Function.Receiver}}.{{$rel.LocalTable.ColumnNameGo}}),
|
||||||
)
|
)
|
||||||
{{else -}}
|
{{else -}}
|
||||||
queryMods = append(queryMods,
|
queryMods = append(queryMods,
|
||||||
qm.Where(`"{{id 0}}"."{{.ForeignColumn}}"=$1`, {{.Column | titleCase | printf "%s.%s" $rel.Function.Receiver }}),
|
qm.Where(`"{{id 0}}"."{{.ForeignColumn}}"=$1`, {{$rel.Function.Receiver}}.{{$rel.LocalTable.ColumnNameGo}}),
|
||||||
)
|
)
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
{{- $slice := printf "%sSlice" .LocalTable.NameGo -}}
|
{{- $slice := printf "%sSlice" .LocalTable.NameGo -}}
|
||||||
// Load{{.Function.Name}} allows an eager lookup of values, cached into the
|
// Load{{.Function.Name}} allows an eager lookup of values, cached into the
|
||||||
// loaded structs of the objects.
|
// loaded structs of the objects.
|
||||||
func (r *{{.LocalTable.NameGo}}Loaded) Load{{.Function.Name}}(e boil.Executor, singular bool, {{$arg}} interface{}) error {
|
func (r *{{.LocalTable.NameGo}}R) Load{{.Function.Name}}(e boil.Executor, singular bool, {{$arg}} interface{}) error {
|
||||||
var slice []*{{.LocalTable.NameGo}}
|
var slice []*{{.LocalTable.NameGo}}
|
||||||
var object *{{.LocalTable.NameGo}}
|
var object *{{.LocalTable.NameGo}}
|
||||||
|
|
||||||
|
@ -45,20 +45,20 @@ func (r *{{.LocalTable.NameGo}}Loaded) Load{{.Function.Name}}(e boil.Executor, s
|
||||||
}
|
}
|
||||||
|
|
||||||
if singular && len(resultSlice) != 0 {
|
if singular && len(resultSlice) != 0 {
|
||||||
if object.Loaded == nil {
|
if object.R == nil {
|
||||||
object.Loaded = &{{.LocalTable.NameGo}}Loaded{}
|
object.R = &{{.LocalTable.NameGo}}R{}
|
||||||
}
|
}
|
||||||
object.Loaded.{{.Function.Name}} = resultSlice[0]
|
object.R.{{.Function.Name}} = resultSlice[0]
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, foreign := range resultSlice {
|
for _, foreign := range resultSlice {
|
||||||
for _, local := range slice {
|
for _, local := range slice {
|
||||||
if local.{{.Function.LocalAssignment}} == foreign.{{.Function.ForeignAssignment}} {
|
if local.{{.Function.LocalAssignment}} == foreign.{{.Function.ForeignAssignment}} {
|
||||||
if local.Loaded == nil {
|
if local.R == nil {
|
||||||
local.Loaded = &{{.LocalTable.NameGo}}Loaded{}
|
local.R = &{{.LocalTable.NameGo}}R{}
|
||||||
}
|
}
|
||||||
local.Loaded.{{.Function.Name}} = foreign
|
local.R.{{.Function.Name}} = foreign
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
{{- $slice := printf "%sSlice" $rel.LocalTable.NameGo -}}
|
{{- $slice := printf "%sSlice" $rel.LocalTable.NameGo -}}
|
||||||
// Load{{$rel.Function.Name}} allows an eager lookup of values, cached into the
|
// Load{{$rel.Function.Name}} allows an eager lookup of values, cached into the
|
||||||
// loaded structs of the objects.
|
// loaded structs of the objects.
|
||||||
func (r *{{$rel.LocalTable.NameGo}}Loaded) Load{{$rel.Function.Name}}(e boil.Executor, singular bool, {{$arg}} interface{}) error {
|
func (r *{{$rel.LocalTable.NameGo}}R) Load{{$rel.Function.Name}}(e boil.Executor, singular bool, {{$arg}} interface{}) error {
|
||||||
var slice []*{{$rel.LocalTable.NameGo}}
|
var slice []*{{$rel.LocalTable.NameGo}}
|
||||||
var object *{{$rel.LocalTable.NameGo}}
|
var object *{{$rel.LocalTable.NameGo}}
|
||||||
|
|
||||||
|
@ -82,10 +82,10 @@ func (r *{{$rel.LocalTable.NameGo}}Loaded) Load{{$rel.Function.Name}}(e boil.Exe
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
if singular {
|
if singular {
|
||||||
if object.Loaded == nil {
|
if object.R == nil {
|
||||||
object.Loaded = &{{$rel.LocalTable.NameGo}}Loaded{}
|
object.R = &{{$rel.LocalTable.NameGo}}R{}
|
||||||
}
|
}
|
||||||
object.Loaded.{{$rel.Function.Name}} = resultSlice
|
object.R.{{$rel.Function.Name}} = resultSlice
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,10 +94,10 @@ func (r *{{$rel.LocalTable.NameGo}}Loaded) Load{{$rel.Function.Name}}(e boil.Exe
|
||||||
localJoinCol := localJoinCols[i]
|
localJoinCol := localJoinCols[i]
|
||||||
for _, local := range slice {
|
for _, local := range slice {
|
||||||
if local.{{$rel.Function.LocalAssignment}} == localJoinCol {
|
if local.{{$rel.Function.LocalAssignment}} == localJoinCol {
|
||||||
if local.Loaded == nil {
|
if local.R == nil {
|
||||||
local.Loaded = &{{$rel.LocalTable.NameGo}}Loaded{}
|
local.R = &{{$rel.LocalTable.NameGo}}R{}
|
||||||
}
|
}
|
||||||
local.Loaded.{{$rel.Function.Name}} = append(local.Loaded.{{$rel.Function.Name}}, foreign)
|
local.R.{{$rel.Function.Name}} = append(local.R.{{$rel.Function.Name}}, foreign)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,10 +106,10 @@ func (r *{{$rel.LocalTable.NameGo}}Loaded) Load{{$rel.Function.Name}}(e boil.Exe
|
||||||
for _, foreign := range resultSlice {
|
for _, foreign := range resultSlice {
|
||||||
for _, local := range slice {
|
for _, local := range slice {
|
||||||
if local.{{$rel.Function.LocalAssignment}} == foreign.{{$rel.Function.ForeignAssignment}} {
|
if local.{{$rel.Function.LocalAssignment}} == foreign.{{$rel.Function.ForeignAssignment}} {
|
||||||
if local.Loaded == nil {
|
if local.R == nil {
|
||||||
local.Loaded = &{{$rel.LocalTable.NameGo}}Loaded{}
|
local.R = &{{$rel.LocalTable.NameGo}}R{}
|
||||||
}
|
}
|
||||||
local.Loaded.{{$rel.Function.Name}} = append(local.Loaded.{{$rel.Function.Name}}, foreign)
|
local.R.{{$rel.Function.Name}} = append(local.R.{{$rel.Function.Name}}, foreign)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
216
templates/relationship_to_many_setops.tpl
Normal file
216
templates/relationship_to_many_setops.tpl
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
{{- if .Table.IsJoinTable -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $dot := . -}}
|
||||||
|
{{- $table := .Table -}}
|
||||||
|
{{- range .Table.ToManyRelationships -}}
|
||||||
|
{{- $varNameSingular := .ForeignTable | singular | camelCase -}}
|
||||||
|
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}}
|
||||||
|
{{- template "relationship_to_one_setops_helper" (textsFromOneToOneRelationship $dot.PkgName $dot.Tables $table .) -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $rel := textsFromRelationship $dot.Tables $table .}}
|
||||||
|
|
||||||
|
// Add{{$rel.Function.Name}} adds the given related objects to the existing relationships
|
||||||
|
// of the {{$table.Name | singular}}, optionally inserting them as new records.
|
||||||
|
// Appends related to {{$rel.Function.Receiver}}.R.{{$rel.Function.Name}}.
|
||||||
|
// 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 {
|
||||||
|
var err error
|
||||||
|
for _, rel := range related {
|
||||||
|
{{if not .ToJoinTable -}}
|
||||||
|
rel.{{$rel.Function.ForeignAssignment}} = {{$rel.Function.Receiver}}.{{$rel.Function.LocalAssignment}}
|
||||||
|
{{if .ForeignColumnNullable -}}
|
||||||
|
rel.{{$rel.ForeignTable.ColumnNameGo}}.Valid = true
|
||||||
|
{{end -}}
|
||||||
|
{{end -}}
|
||||||
|
if insert {
|
||||||
|
if err = rel.Insert(exec); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to insert into foreign table")
|
||||||
|
}
|
||||||
|
}{{if not .ToJoinTable}} else {
|
||||||
|
if err = rel.Update(exec, "{{.ForeignColumn}}"); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to update foreign table")
|
||||||
|
}
|
||||||
|
}{{end -}}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{if .ToJoinTable -}}
|
||||||
|
for _, rel := range related {
|
||||||
|
query := `insert into "{{.JoinTable}}" ({{.JoinLocalColumn}}, {{.JoinForeignColumn}}) values ($1, $2)`
|
||||||
|
values := []interface{}{{"{"}}{{$rel.Function.Receiver}}.{{$rel.LocalTable.ColumnNameGo}}, rel.{{$rel.ForeignTable.ColumnNameGo}}}
|
||||||
|
|
||||||
|
if boil.DebugMode {
|
||||||
|
fmt.Fprintln(boil.DebugWriter, query)
|
||||||
|
fmt.Fprintln(boil.DebugWriter, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = exec.Exec(query, values...)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to insert into join table")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{end -}}
|
||||||
|
|
||||||
|
if {{$rel.Function.Receiver}}.R == nil {
|
||||||
|
{{$rel.Function.Receiver}}.R = &{{$rel.LocalTable.NameGo}}R{
|
||||||
|
{{$rel.Function.Name}}: related,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
{{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} = append({{$rel.Function.Receiver}}.R.{{$rel.Function.Name}}, related...)
|
||||||
|
}
|
||||||
|
|
||||||
|
{{if .ToJoinTable -}}
|
||||||
|
for _, rel := range related {
|
||||||
|
if rel.R == nil {
|
||||||
|
rel.R = &{{$rel.ForeignTable.NameGo}}R{
|
||||||
|
{{$rel.Function.ForeignName}}: {{$rel.LocalTable.NameGo}}Slice{{"{"}}{{$rel.Function.Receiver}}{{"}"}},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rel.R.{{$rel.Function.ForeignName}} = append(rel.R.{{$rel.Function.ForeignName}}, {{$rel.Function.Receiver}})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{else -}}
|
||||||
|
for _, rel := range related {
|
||||||
|
if rel.R == nil {
|
||||||
|
rel.R = &{{$rel.ForeignTable.NameGo}}R{
|
||||||
|
{{$rel.Function.ForeignName}}: {{$rel.Function.Receiver}},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rel.R.{{$rel.Function.ForeignName}} = {{$rel.Function.Receiver}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{end -}}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
{{- if .ForeignColumnNullable}}
|
||||||
|
|
||||||
|
// Set{{$rel.Function.Name}} removes all previously related items of the
|
||||||
|
// {{$table.Name | singular}} replacing them completely with the passed
|
||||||
|
// in related items, optionally inserting them as new records.
|
||||||
|
// Sets {{$rel.Function.Receiver}}.R.{{$rel.Function.ForeignName}}'s {{$rel.Function.Name}} accordingly.
|
||||||
|
// Replaces {{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} with related.
|
||||||
|
// 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 {
|
||||||
|
{{if .ToJoinTable -}}
|
||||||
|
query := `delete from "{{.JoinTable}}" where "{{.JoinLocalColumn}}" = $1`
|
||||||
|
values := []interface{}{{"{"}}{{$rel.Function.Receiver}}.{{$rel.LocalTable.ColumnNameGo}}}
|
||||||
|
{{else -}}
|
||||||
|
query := `update "{{.ForeignTable}}" set "{{.ForeignColumn}}" = null where "{{.ForeignColumn}}" = $1`
|
||||||
|
values := []interface{}{{"{"}}{{$rel.Function.Receiver}}.{{$rel.LocalTable.ColumnNameGo}}}
|
||||||
|
{{end -}}
|
||||||
|
if boil.DebugMode {
|
||||||
|
fmt.Fprintln(boil.DebugWriter, query)
|
||||||
|
fmt.Fprintln(boil.DebugWriter, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := exec.Exec(query, values...)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to remove relationships before set")
|
||||||
|
}
|
||||||
|
|
||||||
|
{{if .ToJoinTable -}}
|
||||||
|
remove{{$rel.LocalTable.NameGo}}From{{$rel.ForeignTable.NameGo}}Slice({{$rel.Function.Receiver}}, related)
|
||||||
|
{{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} = nil
|
||||||
|
{{else -}}
|
||||||
|
if {{$rel.Function.Receiver}}.R != nil {
|
||||||
|
for _, rel := range {{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} {
|
||||||
|
rel.{{$rel.ForeignTable.ColumnNameGo}}.Valid = false
|
||||||
|
if rel.R == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
rel.R.{{$rel.Function.ForeignName}} = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
{{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} = nil
|
||||||
|
}
|
||||||
|
{{end -}}
|
||||||
|
|
||||||
|
return {{$rel.Function.Receiver}}.Add{{$rel.Function.Name}}(exec, insert, related...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
// 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 {
|
||||||
|
var err error
|
||||||
|
{{if .ToJoinTable -}}
|
||||||
|
query := fmt.Sprintf(
|
||||||
|
`delete from "{{.JoinTable}}" where "{{.JoinLocalColumn}}" = $1 and "{{.JoinForeignColumn}}" in (%s)`,
|
||||||
|
strmangle.Placeholders(len(related), 1, 1),
|
||||||
|
)
|
||||||
|
values := []interface{}{{"{"}}{{$rel.Function.Receiver}}.{{$rel.LocalTable.ColumnNameGo}}}
|
||||||
|
|
||||||
|
if boil.DebugMode {
|
||||||
|
fmt.Fprintln(boil.DebugWriter, query)
|
||||||
|
fmt.Fprintln(boil.DebugWriter, values)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = exec.Exec(query, values...)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to remove relationships before set")
|
||||||
|
}
|
||||||
|
{{else -}}
|
||||||
|
for _, rel := range related {
|
||||||
|
rel.{{$rel.ForeignTable.ColumnNameGo}}.Valid = false
|
||||||
|
{{if not .ToJoinTable -}}
|
||||||
|
if rel.R != nil {
|
||||||
|
rel.R.{{$rel.Function.ForeignName}} = nil
|
||||||
|
}
|
||||||
|
{{end -}}
|
||||||
|
if err = rel.Update(exec, "{{.ForeignColumn}}"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{end -}}
|
||||||
|
|
||||||
|
{{if .ToJoinTable -}}
|
||||||
|
remove{{$rel.LocalTable.NameGo}}From{{$rel.ForeignTable.NameGo}}Slice({{$rel.Function.Receiver}}, related)
|
||||||
|
{{end -}}
|
||||||
|
if {{$rel.Function.Receiver}}.R == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rel := range related {
|
||||||
|
for i, ri := range {{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} {
|
||||||
|
if rel != ri {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ln := len({{$rel.Function.Receiver}}.R.{{$rel.Function.Name}})
|
||||||
|
if ln > 1 && i < ln-1 {
|
||||||
|
{{$rel.Function.Receiver}}.R.{{$rel.Function.Name}}[i] = {{$rel.Function.Receiver}}.R.{{$rel.Function.Name}}[ln-1]
|
||||||
|
}
|
||||||
|
{{$rel.Function.Receiver}}.R.{{$rel.Function.Name}} = {{$rel.Function.Receiver}}.R.{{$rel.Function.Name}}[:ln-1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
{{if .ToJoinTable -}}
|
||||||
|
func remove{{$rel.LocalTable.NameGo}}From{{$rel.ForeignTable.NameGo}}Slice({{$rel.Function.Receiver}} *{{$rel.LocalTable.NameGo}}, related []*{{$rel.ForeignTable.NameGo}}) {
|
||||||
|
for _, rel := range related {
|
||||||
|
if rel.R == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for i, ri := range rel.R.{{$rel.Function.ForeignName}} {
|
||||||
|
if {{$rel.Function.Receiver}}.{{$rel.Function.LocalAssignment}} != ri.{{$rel.Function.LocalAssignment}} {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ln := len(rel.R.{{$rel.Function.ForeignName}})
|
||||||
|
if ln > 1 && i < ln-1 {
|
||||||
|
rel.R.{{$rel.Function.ForeignName}}[i] = rel.R.{{$rel.Function.ForeignName}}[ln-1]
|
||||||
|
}
|
||||||
|
rel.R.{{$rel.Function.ForeignName}} = rel.R.{{$rel.Function.ForeignName}}[:ln-1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{end -}}{{- /* if join table */ -}}
|
||||||
|
{{- end -}}{{- /* if nullable foreign key */ -}}
|
||||||
|
{{- end -}}{{- /* if unique foreign key */ -}}
|
||||||
|
{{- end -}}{{- /* range relationships */ -}}
|
||||||
|
{{- end -}}{{- /* outer if join table */ -}}
|
103
templates/relationship_to_one_setops.tpl
Normal file
103
templates/relationship_to_one_setops.tpl
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
{{- define "relationship_to_one_setops_helper" -}}
|
||||||
|
{{- $varNameSingular := .ForeignKey.ForeignTable | 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 = &{{.LocalTable.NameGo}}R{
|
||||||
|
{{.Function.Name}}: related,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
{{.Function.Receiver}}.R.{{.Function.Name}} = related
|
||||||
|
}
|
||||||
|
|
||||||
|
{{if (or .ForeignKey.Unique .Function.OneToOne) -}}
|
||||||
|
if related.R == nil {
|
||||||
|
related.R = &{{.ForeignTable.NameGo}}R{
|
||||||
|
{{.Function.ForeignName}}: {{.Function.Receiver}},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
related.R.{{.Function.ForeignName}} = {{.Function.Receiver}}
|
||||||
|
}
|
||||||
|
{{else -}}
|
||||||
|
if related.R == nil {
|
||||||
|
related.R = &{{.ForeignTable.NameGo}}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")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, rel := range related {
|
||||||
|
if rel.R == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
{{if .ForeignKey.Unique -}}
|
||||||
|
rel.R.{{.Function.ForeignName}} = nil
|
||||||
|
{{else -}}
|
||||||
|
for i, ri := range rel.R.{{.Function.ForeignName}} {
|
||||||
|
if {{.Function.Receiver}}.{{.Function.LocalAssignment}} != ri.{{.Function.LocalAssignment}} {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ln := len(rel.R.{{.Function.ForeignName}})
|
||||||
|
if ln > 1 && i < ln-1 {
|
||||||
|
rel.R.{{.Function.ForeignName}}[i], rel.R.{{.Function.ForeignName}}[ln-1] =
|
||||||
|
rel.R.{{.Function.ForeignName}}[ln-1], rel.R.{{.Function.ForeignName}}[i]
|
||||||
|
}
|
||||||
|
rel.R.{{.Function.ForeignName}} = rel.R.{{.Function.ForeignName}}[:ln-1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
{{end -}}
|
||||||
|
}
|
||||||
|
|
||||||
|
{{.Function.Receiver}}.R.{{.Function.Name}} = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
{{end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- if .Table.IsJoinTable -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $dot := . -}}
|
||||||
|
{{- range .Table.FKeys -}}
|
||||||
|
{{- $rel := textsFromForeignKey $dot.PkgName $dot.Tables $dot.Table . -}}
|
||||||
|
{{- template "relationship_to_one_setops_helper" $rel -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
|
@ -41,11 +41,11 @@ func test{{$rel.LocalTable.NameGo}}ToMany{{$rel.Function.Name}}(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
{{if .ToJoinTable -}}
|
{{if .ToJoinTable -}}
|
||||||
_, err = tx.Exec(`insert into {{.JoinTable}} ({{.JoinLocalColumn}}, {{.JoinForeignColumn}}) values ($1, $2)`, a.{{.Column | titleCase}}, b.{{.ForeignColumn | titleCase}})
|
_, err = tx.Exec(`insert into "{{.JoinTable}}" ({{.JoinLocalColumn}}, {{.JoinForeignColumn}}) values ($1, $2)`, a.{{$rel.LocalTable.ColumnNameGo}}, b.{{$rel.ForeignTable.ColumnNameGo}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
_, err = tx.Exec(`insert into {{.JoinTable}} ({{.JoinLocalColumn}}, {{.JoinForeignColumn}}) values ($1, $2)`, a.{{.Column | titleCase}}, c.{{.ForeignColumn | titleCase}})
|
_, err = tx.Exec(`insert into "{{.JoinTable}}" ({{.JoinLocalColumn}}, {{.JoinForeignColumn}}) values ($1, $2)`, a.{{$rel.LocalTable.ColumnNameGo}}, c.{{$rel.ForeignTable.ColumnNameGo}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -75,18 +75,18 @@ func test{{$rel.LocalTable.NameGo}}ToMany{{$rel.Function.Name}}(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
slice := {{$rel.LocalTable.NameGo}}Slice{&a}
|
slice := {{$rel.LocalTable.NameGo}}Slice{&a}
|
||||||
if err = a.Loaded.Load{{$rel.Function.Name}}(tx, false, &slice); err != nil {
|
if err = a.R.Load{{$rel.Function.Name}}(tx, false, &slice); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if got := len(a.Loaded.{{$rel.Function.Name}}); got != 2 {
|
if got := len(a.R.{{$rel.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.Loaded.{{$rel.Function.Name}} = nil
|
a.R.{{$rel.Function.Name}} = nil
|
||||||
if err = a.Loaded.Load{{$rel.Function.Name}}(tx, true, &a); err != nil {
|
if err = a.R.Load{{$rel.Function.Name}}(tx, true, &a); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if got := len(a.Loaded.{{$rel.Function.Name}}); got != 2 {
|
if got := len(a.R.{{$rel.Function.Name}}); got != 2 {
|
||||||
t.Error("number of eager loaded records wrong, got:", got)
|
t.Error("number of eager loaded records wrong, got:", got)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
308
templates_test/relationship_to_many_setops.tpl
Normal file
308
templates_test/relationship_to_many_setops.tpl
Normal file
|
@ -0,0 +1,308 @@
|
||||||
|
{{- if .Table.IsJoinTable -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $dot := . -}}
|
||||||
|
{{- $table := .Table -}}
|
||||||
|
{{- range .Table.ToManyRelationships -}}
|
||||||
|
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}}
|
||||||
|
{{- template "relationship_to_one_setops_test_helper" (textsFromOneToOneRelationship $dot.PkgName $dot.Tables $table .) -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $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) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
tx := MustTx(boil.Begin())
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
var a {{$rel.LocalTable.NameGo}}
|
||||||
|
var b, c, d, e {{$rel.ForeignTable.NameGo}}
|
||||||
|
|
||||||
|
seed := randomize.NewSeed()
|
||||||
|
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, {{$varNameSingular}}PrimaryKeyColumns...); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
foreigners := []*{{$rel.ForeignTable.NameGo}}{&b, &c, &d, &e}
|
||||||
|
for _, x := range foreigners {
|
||||||
|
if err = randomize.Struct(seed, x, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}PrimaryKeyColumns...); 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)
|
||||||
|
}
|
||||||
|
if err = c.Insert(tx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
foreignersSplitByInsertion := [][]*{{$rel.ForeignTable.NameGo}}{
|
||||||
|
{&b, &c},
|
||||||
|
{&d, &e},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, x := range foreignersSplitByInsertion {
|
||||||
|
err = a.Add{{$rel.Function.Name}}(tx, i != 0, x...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
first := x[0]
|
||||||
|
second := x[1]
|
||||||
|
{{- if .ToJoinTable}}
|
||||||
|
|
||||||
|
if first.R.{{$rel.Function.ForeignName}}[0] != &a {
|
||||||
|
t.Error("relationship was not added properly to the slice")
|
||||||
|
}
|
||||||
|
if second.R.{{$rel.Function.ForeignName}}[0] != &a {
|
||||||
|
t.Error("relationship was not added properly to the slice")
|
||||||
|
}
|
||||||
|
{{- else}}
|
||||||
|
|
||||||
|
if 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}} {
|
||||||
|
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, second.{{$rel.Function.ForeignAssignment}})
|
||||||
|
}
|
||||||
|
|
||||||
|
if first.R.{{$rel.Function.ForeignName}} != &a {
|
||||||
|
t.Error("relationship was not added properly to the foreign slice")
|
||||||
|
}
|
||||||
|
if second.R.{{$rel.Function.ForeignName}} != &a {
|
||||||
|
t.Error("relationship was not added properly to the foreign slice")
|
||||||
|
}
|
||||||
|
{{- end}}
|
||||||
|
|
||||||
|
if a.R.{{$rel.Function.Name}}[i*2] != first {
|
||||||
|
t.Error("relationship struct slice not set to correct value")
|
||||||
|
}
|
||||||
|
if a.R.{{$rel.Function.Name}}[i*2+1] != second {
|
||||||
|
t.Error("relationship struct slice not set to correct value")
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err := a.{{$rel.Function.Name}}(tx).Count()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if want := int64((i+1)*2); count != want {
|
||||||
|
t.Error("want", want, "got", count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{if .ForeignColumnNullable}}
|
||||||
|
|
||||||
|
func test{{$rel.LocalTable.NameGo}}ToManySetOp{{$rel.Function.Name}}(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
tx := MustTx(boil.Begin())
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
var a {{$rel.LocalTable.NameGo}}
|
||||||
|
var b, c, d, e {{$rel.ForeignTable.NameGo}}
|
||||||
|
|
||||||
|
seed := randomize.NewSeed()
|
||||||
|
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, {{$varNameSingular}}PrimaryKeyColumns...); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
foreigners := []*{{$rel.ForeignTable.NameGo}}{&b, &c, &d, &e}
|
||||||
|
for _, x := range foreigners {
|
||||||
|
if err = randomize.Struct(seed, x, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}PrimaryKeyColumns...); 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)
|
||||||
|
}
|
||||||
|
if err = c.Insert(tx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Set{{$rel.Function.Name}}(tx, false, &b, &c)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err := a.{{$rel.Function.Name}}(tx).Count()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if count != 2 {
|
||||||
|
t.Error("count was wrong:", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Set{{$rel.Function.Name}}(tx, true, &d, &e)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err = a.{{$rel.Function.Name}}(tx).Count()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if count != 2 {
|
||||||
|
t.Error("count was wrong:", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
{{- if .ToJoinTable}}
|
||||||
|
|
||||||
|
if len(b.R.{{$rel.Function.ForeignName}}) != 0 {
|
||||||
|
t.Error("relationship was not removed properly from the slice")
|
||||||
|
}
|
||||||
|
if len(c.R.{{$rel.Function.ForeignName}}) != 0 {
|
||||||
|
t.Error("relationship was not removed properly from the slice")
|
||||||
|
}
|
||||||
|
if d.R.{{$rel.Function.ForeignName}}[0] != &a {
|
||||||
|
t.Error("relationship was not added properly to the slice")
|
||||||
|
}
|
||||||
|
if e.R.{{$rel.Function.ForeignName}}[0] != &a {
|
||||||
|
t.Error("relationship was not added properly to the slice")
|
||||||
|
}
|
||||||
|
{{- else}}
|
||||||
|
|
||||||
|
if b.{{$rel.ForeignTable.ColumnNameGo}}.Valid {
|
||||||
|
t.Error("want b's foreign key value to be nil")
|
||||||
|
}
|
||||||
|
if c.{{$rel.ForeignTable.ColumnNameGo}}.Valid {
|
||||||
|
t.Error("want c's foreign key value to be nil")
|
||||||
|
}
|
||||||
|
if 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}} {
|
||||||
|
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, e.{{$rel.Function.ForeignAssignment}})
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.R.{{$rel.Function.ForeignName}} != nil {
|
||||||
|
t.Error("relationship was not removed properly from the foreign struct")
|
||||||
|
}
|
||||||
|
if c.R.{{$rel.Function.ForeignName}} != nil {
|
||||||
|
t.Error("relationship was not removed properly from the foreign struct")
|
||||||
|
}
|
||||||
|
if d.R.{{$rel.Function.ForeignName}} != &a {
|
||||||
|
t.Error("relationship was not added properly to the foreign struct")
|
||||||
|
}
|
||||||
|
if e.R.{{$rel.Function.ForeignName}} != &a {
|
||||||
|
t.Error("relationship was not added properly to the foreign struct")
|
||||||
|
}
|
||||||
|
{{- end}}
|
||||||
|
|
||||||
|
if a.R.{{$rel.Function.Name}}[0] != &d {
|
||||||
|
t.Error("relationship struct slice not set to correct value")
|
||||||
|
}
|
||||||
|
if a.R.{{$rel.Function.Name}}[1] != &e {
|
||||||
|
t.Error("relationship struct slice not set to correct value")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func test{{$rel.LocalTable.NameGo}}ToManyRemoveOp{{$rel.Function.Name}}(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
tx := MustTx(boil.Begin())
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
var a {{$rel.LocalTable.NameGo}}
|
||||||
|
var b, c, d, e {{$rel.ForeignTable.NameGo}}
|
||||||
|
|
||||||
|
seed := randomize.NewSeed()
|
||||||
|
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, {{$varNameSingular}}PrimaryKeyColumns...); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
foreigners := []*{{$rel.ForeignTable.NameGo}}{&b, &c, &d, &e}
|
||||||
|
for _, x := range foreigners {
|
||||||
|
if err = randomize.Struct(seed, x, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}PrimaryKeyColumns...); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := a.Insert(tx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Add{{$rel.Function.Name}}(tx, true, foreigners...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err := a.{{$rel.Function.Name}}(tx).Count()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if count != 4 {
|
||||||
|
t.Error("count was wrong:", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = a.Remove{{$rel.Function.Name}}(tx, foreigners[:2]...)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err = a.{{$rel.Function.Name}}(tx).Count()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if count != 2 {
|
||||||
|
t.Error("count was wrong:", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
{{- if .ToJoinTable}}
|
||||||
|
|
||||||
|
if len(b.R.{{$rel.Function.ForeignName}}) != 0 {
|
||||||
|
t.Error("relationship was not removed properly from the slice")
|
||||||
|
}
|
||||||
|
if len(c.R.{{$rel.Function.ForeignName}}) != 0 {
|
||||||
|
t.Error("relationship was not removed properly from the slice")
|
||||||
|
}
|
||||||
|
if d.R.{{$rel.Function.ForeignName}}[0] != &a {
|
||||||
|
t.Error("relationship was not added properly to the foreign struct")
|
||||||
|
}
|
||||||
|
if e.R.{{$rel.Function.ForeignName}}[0] != &a {
|
||||||
|
t.Error("relationship was not added properly to the foreign struct")
|
||||||
|
}
|
||||||
|
{{- else}}
|
||||||
|
|
||||||
|
if b.{{$rel.ForeignTable.ColumnNameGo}}.Valid {
|
||||||
|
t.Error("want b's foreign key value to be nil")
|
||||||
|
}
|
||||||
|
if c.{{$rel.ForeignTable.ColumnNameGo}}.Valid {
|
||||||
|
t.Error("want c's foreign key value to be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.R.{{$rel.Function.ForeignName}} != nil {
|
||||||
|
t.Error("relationship was not removed properly from the foreign struct")
|
||||||
|
}
|
||||||
|
if c.R.{{$rel.Function.ForeignName}} != nil {
|
||||||
|
t.Error("relationship was not removed properly from the foreign struct")
|
||||||
|
}
|
||||||
|
if d.R.{{$rel.Function.ForeignName}} != &a {
|
||||||
|
t.Error("relationship to a should have been preserved")
|
||||||
|
}
|
||||||
|
if e.R.{{$rel.Function.ForeignName}} != &a {
|
||||||
|
t.Error("relationship to a should have been preserved")
|
||||||
|
}
|
||||||
|
{{- end}}
|
||||||
|
|
||||||
|
if len(a.R.{{$rel.Function.Name}}) != 2 {
|
||||||
|
t.Error("should have preserved two relationships")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removal doesn't do a stable deletion for performance so we have to flip the order
|
||||||
|
if a.R.{{$rel.Function.Name}}[1] != &d {
|
||||||
|
t.Error("relationship to d should have been preserved")
|
||||||
|
}
|
||||||
|
if a.R.{{$rel.Function.Name}}[0] != &e {
|
||||||
|
t.Error("relationship to e should have been preserved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{end -}}
|
||||||
|
{{- end -}}{{- /* if unique foreign key */ -}}
|
||||||
|
{{- end -}}{{- /* range relationships */ -}}
|
||||||
|
{{- end -}}{{- /* outer if join table */ -}}
|
|
@ -12,7 +12,7 @@ func test{{.LocalTable.NameGo}}ToOne{{.ForeignTable.NameGo}}_{{.Function.Name}}(
|
||||||
foreign.{{.ForeignKey.ForeignColumn | titleCase}}.Valid = true
|
foreign.{{.ForeignKey.ForeignColumn | titleCase}}.Valid = true
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
{{if not .Function.ReverseInserts -}}
|
{{if not .Function.OneToOne -}}
|
||||||
if err := foreign.Insert(tx); err != nil {
|
if err := foreign.Insert(tx); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -42,18 +42,18 @@ func test{{.LocalTable.NameGo}}ToOne{{.ForeignTable.NameGo}}_{{.Function.Name}}(
|
||||||
}
|
}
|
||||||
|
|
||||||
slice := {{.LocalTable.NameGo}}Slice{&local}
|
slice := {{.LocalTable.NameGo}}Slice{&local}
|
||||||
if err = local.Loaded.Load{{.Function.Name}}(tx, false, &slice); err != nil {
|
if err = local.R.Load{{.Function.Name}}(tx, false, &slice); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if local.Loaded.{{.Function.Name}} == nil {
|
if local.R.{{.Function.Name}} == nil {
|
||||||
t.Error("struct should have been eager loaded")
|
t.Error("struct should have been eager loaded")
|
||||||
}
|
}
|
||||||
|
|
||||||
local.Loaded.{{.Function.Name}} = nil
|
local.R.{{.Function.Name}} = nil
|
||||||
if err = local.Loaded.Load{{.Function.Name}}(tx, true, &local); err != nil {
|
if err = local.R.Load{{.Function.Name}}(tx, true, &local); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if local.Loaded.{{.Function.Name}} == nil {
|
if local.R.{{.Function.Name}} == nil {
|
||||||
t.Error("struct should have been eager loaded")
|
t.Error("struct should have been eager loaded")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
133
templates_test/relationship_to_one_setops.tpl
Normal file
133
templates_test/relationship_to_one_setops.tpl
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
{{- define "relationship_to_one_setops_test_helper" -}}
|
||||||
|
{{- $varNameSingular := .ForeignKey.Table | singular | camelCase -}}
|
||||||
|
{{- $foreignVarNameSingular := .ForeignKey.ForeignTable | singular | camelCase -}}
|
||||||
|
func test{{.LocalTable.NameGo}}ToOneSetOp{{.ForeignTable.NameGo}}_{{.Function.Name}}(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
tx := MustTx(boil.Begin())
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
var a {{.LocalTable.NameGo}}
|
||||||
|
var b, c {{.ForeignTable.NameGo}}
|
||||||
|
|
||||||
|
seed := randomize.NewSeed()
|
||||||
|
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, {{$varNameSingular}}PrimaryKeyColumns...); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err = randomize.Struct(seed, &b, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}PrimaryKeyColumns...); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err = randomize.Struct(seed, &c, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}PrimaryKeyColumns...); 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 []*{{.ForeignTable.NameGo}}{&b, &c} {
|
||||||
|
err = a.Set{{.Function.Name}}(tx, i != 0, x)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.{{.Function.LocalAssignment}} != x.{{.Function.ForeignAssignment}} {
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
|
zero := reflect.Zero(reflect.TypeOf(a.{{.Function.LocalAssignment}}))
|
||||||
|
reflect.Indirect(reflect.ValueOf(&a.{{.Function.LocalAssignment}})).Set(zero)
|
||||||
|
|
||||||
|
if err = a.Reload(tx); err != nil {
|
||||||
|
t.Fatal("failed to reload", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.{{.Function.LocalAssignment}} != x.{{.Function.ForeignAssignment}} {
|
||||||
|
t.Error("foreign key was wrong value", a.{{.Function.LocalAssignment}}, x.{{.Function.ForeignAssignment}})
|
||||||
|
}
|
||||||
|
|
||||||
|
{{if .ForeignKey.Unique -}}
|
||||||
|
if x.R.{{.Function.ForeignName}} != &a {
|
||||||
|
t.Error("failed to append to foreign relationship struct")
|
||||||
|
}
|
||||||
|
{{else -}}
|
||||||
|
if x.R.{{.Function.ForeignName}}[0] != &a {
|
||||||
|
t.Error("failed to append to foreign relationship struct")
|
||||||
|
}
|
||||||
|
{{end -}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{{- if .ForeignKey.Nullable}}
|
||||||
|
|
||||||
|
func test{{.LocalTable.NameGo}}ToOneRemoveOp{{.ForeignTable.NameGo}}_{{.Function.Name}}(t *testing.T) {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
tx := MustTx(boil.Begin())
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
var a {{.LocalTable.NameGo}}
|
||||||
|
var b {{.ForeignTable.NameGo}}
|
||||||
|
|
||||||
|
seed := randomize.NewSeed()
|
||||||
|
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, {{$varNameSingular}}PrimaryKeyColumns...); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if err = randomize.Struct(seed, &b, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}PrimaryKeyColumns...); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = a.Insert(tx); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = a.Set{{.Function.Name}}(tx, true, &b); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = a.Remove{{.Function.Name}}(tx, &b); err != nil {
|
||||||
|
t.Error("failed to remove relationship")
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err := a.{{.Function.Name}}(tx).Count()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
if count != 0 {
|
||||||
|
t.Error("want no relationships remaining")
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.R.{{.Function.Name}} != nil {
|
||||||
|
t.Error("R struct entry should be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.{{.LocalTable.ColumnNameGo}}.Valid {
|
||||||
|
t.Error("R struct entry should be nil")
|
||||||
|
}
|
||||||
|
|
||||||
|
{{if .ForeignKey.Unique -}}
|
||||||
|
if b.R.{{.Function.ForeignName}} != nil {
|
||||||
|
t.Error("failed to remove a from b's relationships")
|
||||||
|
}
|
||||||
|
{{else -}}
|
||||||
|
if len(b.R.{{.Function.ForeignName}}) != 0 {
|
||||||
|
t.Error("failed to remove a from b's relationships")
|
||||||
|
}
|
||||||
|
{{end -}}
|
||||||
|
}
|
||||||
|
{{end -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- if .Table.IsJoinTable -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $dot := . -}}
|
||||||
|
{{- range .Table.FKeys -}}
|
||||||
|
{{- $rel := textsFromForeignKey $dot.PkgName $dot.Tables $dot.Table .}}
|
||||||
|
|
||||||
|
{{template "relationship_to_one_setops_test_helper" $rel -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
|
@ -138,8 +138,23 @@ func TestInsert(t *testing.T) {
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestToOne tests cannot be run in parallel
|
||||||
|
// or deadlocks can occur.
|
||||||
|
func TestToOne(t *testing.T) {
|
||||||
|
{{- $dot := . -}}
|
||||||
|
{{- range $index, $table := .Tables}}
|
||||||
|
{{- if $table.IsJoinTable -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- range $table.FKeys -}}
|
||||||
|
{{- $rel := textsFromForeignKey $dot.PkgName $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}})
|
||||||
|
{{end -}}{{- /* fkey range */ -}}
|
||||||
|
{{- end -}}{{- /* if join table */ -}}
|
||||||
|
{{- end -}}{{- /* tables range */ -}}
|
||||||
|
}
|
||||||
|
|
||||||
// TestToMany tests cannot be run in parallel
|
// TestToMany tests cannot be run in parallel
|
||||||
// or postgres deadlocks will occur.
|
// or deadlocks can occur.
|
||||||
func TestToMany(t *testing.T) {
|
func TestToMany(t *testing.T) {
|
||||||
{{- $dot := .}}
|
{{- $dot := .}}
|
||||||
{{- range $index, $table := .Tables}}
|
{{- range $index, $table := .Tables}}
|
||||||
|
@ -159,21 +174,105 @@ func TestToMany(t *testing.T) {
|
||||||
{{- end -}}{{- /* outer tables range */ -}}
|
{{- end -}}{{- /* outer tables range */ -}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestToOne tests cannot be run in parallel
|
// TestToOneSet tests cannot be run in parallel
|
||||||
// or postgres deadlocks will occur.
|
// or deadlocks can occur.
|
||||||
func TestToOne(t *testing.T) {
|
func TestToOneSet(t *testing.T) {
|
||||||
{{- $dot := . -}}
|
{{- $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 . -}}
|
{{- $rel := textsFromForeignKey $dot.PkgName $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("{{$rel.LocalTable.NameGo}}To{{$rel.ForeignTable.NameGo}}_{{$rel.Function.Name}}", test{{$rel.LocalTable.NameGo}}ToOneSetOp{{$rel.ForeignTable.NameGo}}_{{$rel.Function.Name}})
|
||||||
{{end -}}{{- /* fkey range */ -}}
|
{{end -}}{{- /* fkey range */ -}}
|
||||||
{{- end -}}{{- /* if join table */ -}}
|
{{- end -}}{{- /* if join table */ -}}
|
||||||
{{- end -}}{{- /* tables range */ -}}
|
{{- end -}}{{- /* tables range */ -}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestToOneRemove tests cannot be run in parallel
|
||||||
|
// or deadlocks can occur.
|
||||||
|
func TestToOneRemove(t *testing.T) {
|
||||||
|
{{- $dot := . -}}
|
||||||
|
{{- range $index, $table := .Tables}}
|
||||||
|
{{- if $table.IsJoinTable -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- range $table.FKeys -}}
|
||||||
|
{{- $rel := textsFromForeignKey $dot.PkgName $dot.Tables $table . -}}
|
||||||
|
{{- if $rel.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}})
|
||||||
|
{{end -}}{{- /* if foreign key nullable */ -}}
|
||||||
|
{{- end -}}{{- /* fkey range */ -}}
|
||||||
|
{{- end -}}{{- /* if join table */ -}}
|
||||||
|
{{- end -}}{{- /* tables range */ -}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestToManyAdd tests cannot be run in parallel
|
||||||
|
// or deadlocks can occur.
|
||||||
|
func TestToManyAdd(t *testing.T) {
|
||||||
|
{{- $dot := .}}
|
||||||
|
{{- range $index, $table := .Tables}}
|
||||||
|
{{- $tableName := $table.Name | plural | titleCase -}}
|
||||||
|
{{- if $table.IsJoinTable -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- range $table.ToManyRelationships -}}
|
||||||
|
{{- $rel := textsFromRelationship $dot.Tables $table . -}}
|
||||||
|
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}}
|
||||||
|
{{- else -}}
|
||||||
|
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 tables range */ -}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestToManySet tests cannot be run in parallel
|
||||||
|
// or deadlocks can occur.
|
||||||
|
func TestToManySet(t *testing.T) {
|
||||||
|
{{- $dot := .}}
|
||||||
|
{{- range $index, $table := .Tables}}
|
||||||
|
{{- $tableName := $table.Name | plural | titleCase -}}
|
||||||
|
{{- if $table.IsJoinTable -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- range $table.ToManyRelationships -}}
|
||||||
|
{{- if not .ForeignColumnNullable -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $rel := textsFromRelationship $dot.Tables $table . -}}
|
||||||
|
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}}
|
||||||
|
{{- $oneToOne := textsFromOneToOneRelationship $dot.PkgName $dot.Tables $table . -}}
|
||||||
|
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 -}}{{- /* outer if join table */ -}}
|
||||||
|
{{- end -}}{{- /* outer tables range */ -}}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestToManyRemove tests cannot be run in parallel
|
||||||
|
// or deadlocks can occur.
|
||||||
|
func TestToManyRemove(t *testing.T) {
|
||||||
|
{{- $dot := .}}
|
||||||
|
{{- range $index, $table := .Tables}}
|
||||||
|
{{- $tableName := $table.Name | plural | titleCase -}}
|
||||||
|
{{- if $table.IsJoinTable -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- range $table.ToManyRelationships -}}
|
||||||
|
{{- if not .ForeignColumnNullable -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- $rel := textsFromRelationship $dot.Tables $table . -}}
|
||||||
|
{{- if (and .ForeignColumnUnique (not .ToJoinTable)) -}}
|
||||||
|
{{- $oneToOne := textsFromOneToOneRelationship $dot.PkgName $dot.Tables $table . -}}
|
||||||
|
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 -}}{{- /* outer if join table */ -}}
|
||||||
|
{{- end -}}{{- /* outer tables range */ -}}
|
||||||
|
}
|
||||||
|
|
||||||
func TestReload(t *testing.T) {
|
func TestReload(t *testing.T) {
|
||||||
{{- range $index, $table := .Tables}}
|
{{- range $index, $table := .Tables}}
|
||||||
{{- if $table.IsJoinTable -}}
|
{{- if $table.IsJoinTable -}}
|
||||||
|
|
|
@ -28,10 +28,11 @@ type RelationshipToOneTexts struct {
|
||||||
Function struct {
|
Function struct {
|
||||||
PackageName string
|
PackageName string
|
||||||
Name string
|
Name string
|
||||||
|
ForeignName string
|
||||||
|
|
||||||
Varname string
|
Varname string
|
||||||
Receiver string
|
Receiver string
|
||||||
ReverseInserts bool
|
OneToOne bool
|
||||||
|
|
||||||
LocalAssignment string
|
LocalAssignment string
|
||||||
ForeignAssignment string
|
ForeignAssignment string
|
||||||
|
@ -54,6 +55,11 @@ func textsFromForeignKey(packageName string, tables []bdb.Table, table bdb.Table
|
||||||
|
|
||||||
r.Function.PackageName = packageName
|
r.Function.PackageName = packageName
|
||||||
r.Function.Name = strmangle.TitleCase(strmangle.Singular(strings.TrimSuffix(fkey.Column, "_id")))
|
r.Function.Name = strmangle.TitleCase(strmangle.Singular(strings.TrimSuffix(fkey.Column, "_id")))
|
||||||
|
plurality := strmangle.Plural
|
||||||
|
if fkey.Unique {
|
||||||
|
plurality = strmangle.Singular
|
||||||
|
}
|
||||||
|
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])
|
r.Function.Receiver = strings.ToLower(table.Name[:1])
|
||||||
|
|
||||||
|
@ -91,7 +97,8 @@ func textsFromOneToOneRelationship(packageName string, tables []bdb.Table, table
|
||||||
|
|
||||||
rel := textsFromForeignKey(packageName, tables, table, fkey)
|
rel := textsFromForeignKey(packageName, tables, table, fkey)
|
||||||
rel.Function.Name = strmangle.TitleCase(strmangle.Singular(toMany.ForeignTable))
|
rel.Function.Name = strmangle.TitleCase(strmangle.Singular(toMany.ForeignTable))
|
||||||
rel.Function.ReverseInserts = true
|
rel.Function.ForeignName = mkFunctionName(strmangle.Singular(toMany.Table), strmangle.TitleCase(strmangle.Singular(toMany.Table)), toMany.ForeignColumn, false)
|
||||||
|
rel.Function.OneToOne = true
|
||||||
return rel
|
return rel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +107,7 @@ type RelationshipToManyTexts struct {
|
||||||
LocalTable struct {
|
LocalTable struct {
|
||||||
NameGo string
|
NameGo string
|
||||||
NameSingular string
|
NameSingular string
|
||||||
|
ColumnNameGo string
|
||||||
}
|
}
|
||||||
|
|
||||||
ForeignTable struct {
|
ForeignTable struct {
|
||||||
|
@ -107,11 +115,13 @@ type RelationshipToManyTexts struct {
|
||||||
NameSingular string
|
NameSingular string
|
||||||
NamePluralGo string
|
NamePluralGo string
|
||||||
NameHumanReadable string
|
NameHumanReadable string
|
||||||
|
ColumnNameGo string
|
||||||
Slice string
|
Slice string
|
||||||
}
|
}
|
||||||
|
|
||||||
Function struct {
|
Function struct {
|
||||||
Name string
|
Name string
|
||||||
|
ForeignName string
|
||||||
Receiver string
|
Receiver string
|
||||||
|
|
||||||
LocalAssignment string
|
LocalAssignment string
|
||||||
|
@ -125,23 +135,24 @@ func textsFromRelationship(tables []bdb.Table, table bdb.Table, rel bdb.ToManyRe
|
||||||
r := RelationshipToManyTexts{}
|
r := RelationshipToManyTexts{}
|
||||||
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.ForeignTable.NameSingular = strmangle.Singular(rel.ForeignTable)
|
r.ForeignTable.NameSingular = strmangle.Singular(rel.ForeignTable)
|
||||||
r.ForeignTable.NamePluralGo = strmangle.TitleCase(strmangle.Plural(rel.ForeignTable))
|
r.ForeignTable.NamePluralGo = strmangle.TitleCase(strmangle.Plural(rel.ForeignTable))
|
||||||
r.ForeignTable.NameGo = strmangle.TitleCase(r.ForeignTable.NameSingular)
|
r.ForeignTable.NameGo = strmangle.TitleCase(r.ForeignTable.NameSingular)
|
||||||
|
r.ForeignTable.ColumnNameGo = strmangle.TitleCase(rel.ForeignColumn)
|
||||||
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.Receiver = strings.ToLower(table.Name[:1])
|
||||||
|
r.Function.Name = mkFunctionName(r.LocalTable.NameSingular, r.ForeignTable.NamePluralGo, rel.ForeignColumn, rel.ToJoinTable)
|
||||||
// Check to see if the foreign key name is the same as the local table name.
|
plurality := strmangle.Singular
|
||||||
// Simple case: yes - we can name the function the same as the plural table name
|
foreignNamingColumn := rel.ForeignColumn
|
||||||
// Not simple case: We have to name the function based off the foreign key and
|
if rel.ToJoinTable {
|
||||||
if colName := strings.TrimSuffix(rel.ForeignColumn, "_id"); rel.ToJoinTable || r.LocalTable.NameSingular == colName {
|
plurality = strmangle.Plural
|
||||||
r.Function.Name = r.ForeignTable.NamePluralGo
|
foreignNamingColumn = rel.JoinLocalColumn
|
||||||
} else {
|
|
||||||
r.Function.Name = strmangle.TitleCase(colName) + r.ForeignTable.NamePluralGo
|
|
||||||
}
|
}
|
||||||
|
r.Function.ForeignName = strmangle.TitleCase(plurality(strings.TrimSuffix(foreignNamingColumn, "_id")))
|
||||||
|
|
||||||
if rel.Nullable {
|
if rel.Nullable {
|
||||||
col := table.GetColumn(rel.Column)
|
col := table.GetColumn(rel.Column)
|
||||||
|
@ -160,3 +171,15 @@ func textsFromRelationship(tables []bdb.Table, table bdb.Table, rel bdb.ToManyRe
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mkFunctionName checks to see if the foreign key name is the same as the local table name (minus _id suffix)
|
||||||
|
// 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
|
||||||
|
func mkFunctionName(fkeyTableSingular, foreignTablePluralGo, fkeyColumn string, toJoinTable bool) string {
|
||||||
|
colName := strings.TrimSuffix(fkeyColumn, "_id")
|
||||||
|
if toJoinTable || fkeyTableSingular == colName {
|
||||||
|
return foreignTablePluralGo
|
||||||
|
}
|
||||||
|
|
||||||
|
return strmangle.TitleCase(colName) + foreignTablePluralGo
|
||||||
|
}
|
||||||
|
|
|
@ -34,9 +34,10 @@ func TestTextsFromForeignKey(t *testing.T) {
|
||||||
|
|
||||||
expect.Function.PackageName = "models"
|
expect.Function.PackageName = "models"
|
||||||
expect.Function.Name = "Pilot"
|
expect.Function.Name = "Pilot"
|
||||||
|
expect.Function.ForeignName = "Jet"
|
||||||
expect.Function.Varname = "pilot"
|
expect.Function.Varname = "pilot"
|
||||||
expect.Function.Receiver = "j"
|
expect.Function.Receiver = "j"
|
||||||
expect.Function.ReverseInserts = false
|
expect.Function.OneToOne = false
|
||||||
|
|
||||||
expect.Function.LocalAssignment = "PilotID.Int"
|
expect.Function.LocalAssignment = "PilotID.Int"
|
||||||
expect.Function.ForeignAssignment = "ID"
|
expect.Function.ForeignAssignment = "ID"
|
||||||
|
@ -44,6 +45,37 @@ func TestTextsFromForeignKey(t *testing.T) {
|
||||||
if !reflect.DeepEqual(expect, texts) {
|
if !reflect.DeepEqual(expect, texts) {
|
||||||
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])
|
||||||
|
expect = RelationshipToOneTexts{}
|
||||||
|
expect.ForeignKey = jets.FKeys[1]
|
||||||
|
|
||||||
|
expect.LocalTable.NameGo = "Jet"
|
||||||
|
expect.LocalTable.ColumnNameGo = "AirportID"
|
||||||
|
|
||||||
|
expect.ForeignTable.Name = "airports"
|
||||||
|
expect.ForeignTable.NameGo = "Airport"
|
||||||
|
expect.ForeignTable.NamePluralGo = "Airports"
|
||||||
|
expect.ForeignTable.ColumnName = "id"
|
||||||
|
expect.ForeignTable.ColumnNameGo = "ID"
|
||||||
|
|
||||||
|
expect.Function.PackageName = "models"
|
||||||
|
expect.Function.Name = "Airport"
|
||||||
|
expect.Function.ForeignName = "Jets"
|
||||||
|
expect.Function.Varname = "airport"
|
||||||
|
expect.Function.Receiver = "j"
|
||||||
|
expect.Function.OneToOne = false
|
||||||
|
|
||||||
|
expect.Function.LocalAssignment = "AirportID"
|
||||||
|
expect.Function.ForeignAssignment = "ID"
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expect, texts) {
|
||||||
|
t.Errorf("Want:\n%s\nGot:\n%s\n", spew.Sdump(expect), spew.Sdump(texts))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(expect, texts) {
|
||||||
|
t.Errorf("Want:\n%s\nGot:\n%s\n", spew.Sdump(expect), spew.Sdump(texts))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTextsFromOneToOneRelationship(t *testing.T) {
|
func TestTextsFromOneToOneRelationship(t *testing.T) {
|
||||||
|
@ -59,7 +91,7 @@ func TestTextsFromOneToOneRelationship(t *testing.T) {
|
||||||
expect := RelationshipToOneTexts{}
|
expect := RelationshipToOneTexts{}
|
||||||
|
|
||||||
expect.ForeignKey = bdb.ForeignKey{
|
expect.ForeignKey = bdb.ForeignKey{
|
||||||
Table: "jets",
|
Table: "pilots",
|
||||||
Name: "none",
|
Name: "none",
|
||||||
Column: "id",
|
Column: "id",
|
||||||
Nullable: false,
|
Nullable: false,
|
||||||
|
@ -82,9 +114,10 @@ func TestTextsFromOneToOneRelationship(t *testing.T) {
|
||||||
|
|
||||||
expect.Function.PackageName = "models"
|
expect.Function.PackageName = "models"
|
||||||
expect.Function.Name = "Jet"
|
expect.Function.Name = "Jet"
|
||||||
|
expect.Function.ForeignName = "Pilot"
|
||||||
expect.Function.Varname = "jet"
|
expect.Function.Varname = "jet"
|
||||||
expect.Function.Receiver = "p"
|
expect.Function.Receiver = "p"
|
||||||
expect.Function.ReverseInserts = true
|
expect.Function.OneToOne = true
|
||||||
|
|
||||||
expect.Function.LocalAssignment = "ID"
|
expect.Function.LocalAssignment = "ID"
|
||||||
expect.Function.ForeignAssignment = "PilotID.Int"
|
expect.Function.ForeignAssignment = "PilotID.Int"
|
||||||
|
@ -107,14 +140,17 @@ func TestTextsFromRelationship(t *testing.T) {
|
||||||
expect := RelationshipToManyTexts{}
|
expect := RelationshipToManyTexts{}
|
||||||
expect.LocalTable.NameGo = "Pilot"
|
expect.LocalTable.NameGo = "Pilot"
|
||||||
expect.LocalTable.NameSingular = "pilot"
|
expect.LocalTable.NameSingular = "pilot"
|
||||||
|
expect.LocalTable.ColumnNameGo = "ID"
|
||||||
|
|
||||||
expect.ForeignTable.NameGo = "Jet"
|
expect.ForeignTable.NameGo = "Jet"
|
||||||
expect.ForeignTable.NameSingular = "jet"
|
expect.ForeignTable.NameSingular = "jet"
|
||||||
expect.ForeignTable.NamePluralGo = "Jets"
|
expect.ForeignTable.NamePluralGo = "Jets"
|
||||||
expect.ForeignTable.NameHumanReadable = "jets"
|
expect.ForeignTable.NameHumanReadable = "jets"
|
||||||
|
expect.ForeignTable.ColumnNameGo = "PilotID"
|
||||||
expect.ForeignTable.Slice = "JetSlice"
|
expect.ForeignTable.Slice = "JetSlice"
|
||||||
|
|
||||||
expect.Function.Name = "Jets"
|
expect.Function.Name = "Jets"
|
||||||
|
expect.Function.ForeignName = "Pilot"
|
||||||
expect.Function.Receiver = "p"
|
expect.Function.Receiver = "p"
|
||||||
expect.Function.LocalAssignment = "ID"
|
expect.Function.LocalAssignment = "ID"
|
||||||
expect.Function.ForeignAssignment = "PilotID.Int"
|
expect.Function.ForeignAssignment = "PilotID.Int"
|
||||||
|
@ -127,14 +163,17 @@ func TestTextsFromRelationship(t *testing.T) {
|
||||||
expect = RelationshipToManyTexts{}
|
expect = RelationshipToManyTexts{}
|
||||||
expect.LocalTable.NameGo = "Pilot"
|
expect.LocalTable.NameGo = "Pilot"
|
||||||
expect.LocalTable.NameSingular = "pilot"
|
expect.LocalTable.NameSingular = "pilot"
|
||||||
|
expect.LocalTable.ColumnNameGo = "ID"
|
||||||
|
|
||||||
expect.ForeignTable.NameGo = "License"
|
expect.ForeignTable.NameGo = "License"
|
||||||
expect.ForeignTable.NameSingular = "license"
|
expect.ForeignTable.NameSingular = "license"
|
||||||
expect.ForeignTable.NamePluralGo = "Licenses"
|
expect.ForeignTable.NamePluralGo = "Licenses"
|
||||||
expect.ForeignTable.NameHumanReadable = "licenses"
|
expect.ForeignTable.NameHumanReadable = "licenses"
|
||||||
|
expect.ForeignTable.ColumnNameGo = "PilotID"
|
||||||
expect.ForeignTable.Slice = "LicenseSlice"
|
expect.ForeignTable.Slice = "LicenseSlice"
|
||||||
|
|
||||||
expect.Function.Name = "Licenses"
|
expect.Function.Name = "Licenses"
|
||||||
|
expect.Function.ForeignName = "Pilot"
|
||||||
expect.Function.Receiver = "p"
|
expect.Function.Receiver = "p"
|
||||||
expect.Function.LocalAssignment = "ID"
|
expect.Function.LocalAssignment = "ID"
|
||||||
expect.Function.ForeignAssignment = "PilotID"
|
expect.Function.ForeignAssignment = "PilotID"
|
||||||
|
@ -147,14 +186,17 @@ func TestTextsFromRelationship(t *testing.T) {
|
||||||
expect = RelationshipToManyTexts{}
|
expect = RelationshipToManyTexts{}
|
||||||
expect.LocalTable.NameGo = "Pilot"
|
expect.LocalTable.NameGo = "Pilot"
|
||||||
expect.LocalTable.NameSingular = "pilot"
|
expect.LocalTable.NameSingular = "pilot"
|
||||||
|
expect.LocalTable.ColumnNameGo = "ID"
|
||||||
|
|
||||||
expect.ForeignTable.NameGo = "Language"
|
expect.ForeignTable.NameGo = "Language"
|
||||||
expect.ForeignTable.NameSingular = "language"
|
expect.ForeignTable.NameSingular = "language"
|
||||||
expect.ForeignTable.NamePluralGo = "Languages"
|
expect.ForeignTable.NamePluralGo = "Languages"
|
||||||
expect.ForeignTable.NameHumanReadable = "languages"
|
expect.ForeignTable.NameHumanReadable = "languages"
|
||||||
|
expect.ForeignTable.ColumnNameGo = "ID"
|
||||||
expect.ForeignTable.Slice = "LanguageSlice"
|
expect.ForeignTable.Slice = "LanguageSlice"
|
||||||
|
|
||||||
expect.Function.Name = "Languages"
|
expect.Function.Name = "Languages"
|
||||||
|
expect.Function.ForeignName = "Pilots"
|
||||||
expect.Function.Receiver = "p"
|
expect.Function.Receiver = "p"
|
||||||
expect.Function.LocalAssignment = "ID"
|
expect.Function.LocalAssignment = "ID"
|
||||||
expect.Function.ForeignAssignment = "ID"
|
expect.Function.ForeignAssignment = "ID"
|
||||||
|
|
Loading…
Reference in a new issue