Isolate to_many from one_to_one in bdb

This commit is contained in:
Aaron L 2016-09-17 23:11:50 -07:00
parent 9bc5b3fa40
commit b918e9ef9e
5 changed files with 182 additions and 94 deletions

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,17 @@
package bdb package bdb
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 +38,67 @@ 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 {
continue
}
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 continue
} }
relationships = append(relationships, buildRelationship(table, f, t, tables)) relationships = append(relationships, buildToManyRelationship(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
} }