🗝️
xo の外部キー関数を uuid.NullUUID に対応させる
xo は PostgreSQL の UUID 型に対応しているが、nullable の UUID 型 (uuid.NullUUID) を参照する外部キー関数はうまく生成できない。
例えば、このようなスキーマから xo でコードを生成した場合、以下のような関数が生成される。
CREATE TABLE areas (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
name VARCHAR(255) NOT NULL
);
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
area_id UUID REFERENCES areas (id) ON DELETE RESTRICT
);
user.xo.go
// Area returns the Area associated with the User's (AreaID).
//
// Generated from foreign key 'users_area_id_fkey'.
func (u *User) Area(ctx context.Context, db DB) (*Area, error) {
return AreaByAreaID(ctx, db, uuid.UUID(u.AreaID)) // <- 👎
}
u.AreaID
は uuid.NullUUID であるため、 uuid.UUID(u.AreaID)
となっている部分でエラーが発生する。そのため、カスタムテンプレートを使用して関数を修正する必要がある。
cannot convert u.AreaID (variable of type uuid.NullUUID) to type uuid.UUID
解決策
まず、 xo の template を dump する。
xo dump xo/templates
templates/go.go
にある convertTypes()
を変更する。
xo/templates/go.go
func (f *Funcs) convertTypes(fkey ForeignKey) string {
var p []string
for i := range fkey.Fields {
field := fkey.Fields[i]
refField := fkey.RefFields[i]
expr := f.short(fkey.Table) + "." + field.GoName
// types match, can match
if field.Type == refField.Type {
p = append(p, expr)
continue
}
// convert types
typ, refType := field.Type, refField.Type
if strings.HasPrefix(typ, "sql.Null") {
expr = expr + "." + typ[8:]
typ = strings.ToLower(typ[8:])
} else if typ == "uuid.NullUUID" { // <- ここを追加
expr = expr + ".UUID"
typ = strings.ToLower("uuid.UUID")
}
if strings.ToLower(refType) != typ {
expr = refType + "(" + expr + ")"
}
p = append(p, expr)
}
return strings.Join(p, ", ")
}
編集したカスタムテンプレートを使用してコードを再生成する。
xo schema --src xo/templates
user.xo.go
// Area returns the Area associated with the User's (AreaID).
//
// Generated from foreign key 'users_area_id_fkey'.
func (u *User) Area(ctx context.Context, db DB) (*Area, error) {
return AreaByAreaID(ctx, db, u.AreaID.UUID) // <- 👍
}
Discussion