forked from volatiletech/sqlboiler
-
Notifications
You must be signed in to change notification settings - Fork 0
/
text_helpers.go
141 lines (123 loc) · 3.93 KB
/
text_helpers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package boilingcore
import (
"strings"
"github.com/volatiletech/sqlboiler/drivers"
"github.com/volatiletech/sqlboiler/strmangle"
)
// txtNameToOne creates the local and foreign function names for
// one-to-many and one-to-one relationships, where local is the side with
// the foreign key.
//
// = many-to-one
// users - videos : user_id
// users - videos : producer_id
//
// fk == table = user.Videos | video.User
// fk != table = user.ProducerVideos | video.Producer
//
// = many-to-one
// industries - industries : parent_id
//
// fk == table = industry.Industries | industry.Industry
// fk != table = industry.ParentIndustries | industry.Parent
//
// = one-to-one
// users - videos : user_id
// users - videos : producer_id
//
// fk == table = user.Video | video.User
// fk != table = user.ProducerVideo | video.Producer
//
// = one-to-one
// industries - industries : parent_id
//
// fk == table = industry.Industry | industry.Industry
// fk != table = industry.ParentIndustry | industry.Industry
func txtNameToOne(fk drivers.ForeignKey) (localFn, foreignFn string) {
foreignFn = strmangle.Singular(trimSuffixes(fk.Column))
fkeyNotTableName := foreignFn != strmangle.Singular(fk.ForeignTable)
foreignFn = strmangle.TitleCase(foreignFn)
if fkeyNotTableName {
localFn = foreignFn
}
plurality := strmangle.Plural
if fk.Unique {
plurality = strmangle.Singular
}
localFn += strmangle.TitleCase(plurality(fk.Table))
return localFn, foreignFn
}
// txtNameToMany creates the local and foreign function names for
// many-to-many relationships where there are two foreign keys involved.
//
// The output of the foreign key is the name for that side of the relationship.
//
// | tags | | tags_videos | | videos |
// | id | | tag_id, video_id | | id |
//
// In this setup the lhs is the tag_id foreign key, and so the lhsFn will
// refer to "how to name the lhs" which in this case should be tags. And
// videos for the rhs.
//
// cases:
// sponsors - contests
// sponsor_id contest_id
// fk == table = sponsor.Contests | contest.Sponsors
//
// sponsors - contests
// wiggle_id jiggle_id
// fk != table = sponsor.JiggleSponsors | contest.WiggleContests
//
// industries - industries
// industry_id mapped_industry_id
// fk == table = industry.Industries
// fk != table = industry.MappedIndustryIndustry
func txtNameToMany(lhs, rhs drivers.ForeignKey) (lhsFn, rhsFn string) {
lhsKey := strmangle.Singular(trimSuffixes(lhs.Column))
rhsKey := strmangle.Singular(trimSuffixes(rhs.Column))
if lhsKey != strmangle.Singular(lhs.ForeignTable) {
lhsFn = strmangle.TitleCase(lhsKey)
}
lhsFn += strmangle.TitleCase(strmangle.Plural(lhs.ForeignTable))
if rhsKey != strmangle.Singular(rhs.ForeignTable) {
rhsFn = strmangle.TitleCase(rhsKey)
}
rhsFn += strmangle.TitleCase(strmangle.Plural(rhs.ForeignTable))
return lhsFn, rhsFn
}
// usesPrimitives checks to see if relationship between two models (ie the foreign key column
// and referred to column) both are primitive Go types we can compare or assign with == and =
// in a template.
func usesPrimitives(tables []drivers.Table, table, column, foreignTable, foreignColumn string) bool {
local := drivers.GetTable(tables, table)
foreign := drivers.GetTable(tables, foreignTable)
col := local.GetColumn(column)
foreignCol := foreign.GetColumn(foreignColumn)
return isPrimitive(col.Type) && isPrimitive(foreignCol.Type)
}
var identifierSuffixes = []string{"_id", "_uuid", "_guid", "_oid"}
// trimSuffixes from the identifier
func trimSuffixes(str string) string {
ln := len(str)
for _, s := range identifierSuffixes {
str = strings.TrimSuffix(str, s)
if len(str) != ln {
break
}
}
return str
}
func isPrimitive(typ string) bool {
switch typ {
// Numeric
case "int", "int8", "int16", "int32", "int64":
return true
case "uint", "uint8", "uint16", "uint32", "uint64":
return true
case "float32", "float64":
return true
case "byte", "rune", "string":
return true
}
return false
}