Skip to content

Commit 19ca55d

Browse files
authored
Introduce table reference support. (#16)
1 parent 563c34a commit 19ca55d

13 files changed

Lines changed: 4577 additions & 985 deletions

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@ bins:
99
tests: bins
1010
go test -v -race -covermode=atomic -coverprofile=morph.coverprofile
1111

12+
coverage: tests
13+
go tool cover -html=morph.coverprofile
14+
1215
benchmarks: bins
1316
go test -C internal -run XXX -bench=.

column.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,14 @@ func (c *Column) FieldType() string {
8282
func (c *Column) SetFieldType(fieldType string) {
8383
c.fieldType = strings.TrimSpace(fieldType)
8484
}
85+
86+
// equal checks if two columns are equal.
87+
func (c Column) equals(other Column) bool {
88+
sameName := c.Name() == other.Name()
89+
sameField := c.Field() == other.Field()
90+
sameFieldType := c.FieldType() == other.FieldType()
91+
sameFieldStrategy := c.Strategy() == other.Strategy()
92+
samePrimaryKey := c.PrimaryKey() == other.PrimaryKey()
93+
94+
return sameName && sameField && sameFieldType && sameFieldStrategy && samePrimaryKey
95+
}

configuration.go

Lines changed: 86 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,34 +9,92 @@ type Configuration struct {
99
// AsMetadata converts the configuration to metadata mappings.
1010
func (c Configuration) AsMetadata() []Table {
1111
var tables []Table
12+
13+
references := map[string][]ReferenceConfiguration{}
14+
tablesByName := map[string]*Table{}
15+
columnsByName := map[string]*Column{}
16+
1217
for _, t := range c.Tables {
13-
var table Table
14-
table.SetTypeName(t.TypeName)
15-
table.SetName(t.Name)
16-
table.SetAlias(t.Alias)
17-
for _, c := range t.Columns {
18-
var column Column
19-
column.SetField(c.Field)
20-
column.SetName(c.Name)
21-
column.SetFieldType(c.FieldType)
22-
column.SetStrategy(c.FieldStrategy)
23-
column.SetPrimaryKey(c.PrimaryKey)
24-
if err := table.AddColumn(column); err != nil {
18+
table := t.AsTable()
19+
for _, column := range table.Columns() {
20+
columnsByName[column.Name()] = &column
21+
}
22+
tablesByName[table.Name()] = &table
23+
24+
if len(t.References) > 0 {
25+
if _, ok := references[table.Name()]; !ok {
26+
references[table.Name()] = []ReferenceConfiguration{}
27+
}
28+
references[table.Name()] = append(references[table.Name()], t.References...)
29+
}
30+
}
31+
32+
for childTableName, refs := range references {
33+
child, ok := tablesByName[childTableName]
34+
if !ok {
35+
continue
36+
}
37+
for _, ref := range refs {
38+
parent, ok := tablesByName[ref.TableName]
39+
if !ok {
40+
continue
41+
}
42+
key := []Column{}
43+
for _, fk := range ref.ForeignKey {
44+
if column, ok := columnsByName[fk.ColumnName]; ok {
45+
key = append(key, *column)
46+
}
47+
}
48+
if _, err := child.References(parent, key); err != nil {
2549
continue
2650
}
2751
}
28-
tables = append(tables, table)
2952
}
53+
54+
for _, table := range tablesByName {
55+
tables = append(tables, *table)
56+
}
57+
3058
return tables
3159
}
3260

3361
// TableConfiguration represents the configuration used to construct
3462
// a single table mapping.
3563
type TableConfiguration struct {
36-
TypeName string `json:"typeName" yaml:"typeName"`
37-
Name string `json:"name" yaml:"name"`
38-
Alias string `json:"alias" yaml:"alias"`
39-
Columns []ColumnConfiguration `json:"columns" yaml:"columns"`
64+
TypeName string `json:"typeName" yaml:"typeName"`
65+
Name string `json:"name" yaml:"name"`
66+
Alias string `json:"alias" yaml:"alias"`
67+
Columns []ColumnConfiguration `json:"columns" yaml:"columns"`
68+
References []ReferenceConfiguration `json:"references" yaml:"references"`
69+
}
70+
71+
// AsTable converts the configuration to a table mapping.
72+
func (t TableConfiguration) AsTable() Table {
73+
var table Table
74+
table.SetTypeName(t.TypeName)
75+
table.SetName(t.Name)
76+
table.SetAlias(t.Alias)
77+
78+
for _, c := range t.Columns {
79+
if err := table.AddColumn(c.AsColumn()); err != nil {
80+
continue
81+
}
82+
}
83+
84+
return table
85+
}
86+
87+
// ReferenceConfiguration represents the configuration used to construct
88+
// a single reference between two tables.
89+
type ReferenceConfiguration struct {
90+
TableName string `json:"tableName" yaml:"tableName"`
91+
ForeignKey []ForeignKeyConfiguration `json:"foreignKey" yaml:"foreignKey"`
92+
}
93+
94+
// ForeignKeyConfiguration represents the configuration used to communicate
95+
// which columns comprise the foreign key for a reference.
96+
type ForeignKeyConfiguration struct {
97+
ColumnName string `json:"columnName" yaml:"columnName"`
4098
}
4199

42100
// ColumnConfiguration represents the configuration used to construct
@@ -48,3 +106,14 @@ type ColumnConfiguration struct {
48106
FieldStrategy FieldStrategy `json:"fieldStrategy" yaml:"fieldStrategy"`
49107
PrimaryKey bool `json:"primaryKey" yaml:"primaryKey"`
50108
}
109+
110+
// AsColumn converts the configuration to a column mapping.
111+
func (c ColumnConfiguration) AsColumn() Column {
112+
var column Column
113+
column.SetField(c.Field)
114+
column.SetName(c.Name)
115+
column.SetFieldType(c.FieldType)
116+
column.SetStrategy(c.FieldStrategy)
117+
column.SetPrimaryKey(c.PrimaryKey)
118+
return column
119+
}

0 commit comments

Comments
 (0)