🍙

ent ( entgo.io/ent ) で ULID を使う

2021/03/09に公開

※この内容は https://nazo.hatenablog.com/entry/entgo-ulid と同一です

ent では UUID 型がデフォルトでサポートされているのですが、それとは別に ULID を使う方法を解説します。

ULID の実装は https://github.com/oklog/ulid を使用します。

ent の UUID 型は、driver.Valuer Interface を利用して値を取得しますが、 oklog/ulid の Value() の実装がバイナリを返却するようになっているため、このままでは可読性が悪いです。 Value() が String を返すようにした ULID 型を新たに定義するのが良いでしょう。そのようにすると、他の interface も実装する必要があります。

結論から言うと https://github.com/ent/contrib/blob/6623819401500db45747a2419172963217cef619/entgql/internal/todopulid/ent/schema/pulid/pulid.go にそのものの実装があります[1]。この実装はライブラリ化されているものではない( internal )ので、そのままコピペして利用するのが良いでしょう。

使用する場合には以下のようになります。

// Fields of the User.
func (User) Fields() []ent.Field {
	return []ent.Field{
		field.String("id").
			GoType(pulid.ID("")).
			DefaultFunc(func() pulid.ID { return pulid.MustNew("US") }),
		field.Int("age").Positive(),
		field.String("name").Default("unknown"),
	}
}

prefixが不要な場合はprefixの部分を削ってしまうのが良いかと思います。

このままの実装でもう少し手軽に書きたい場合は、同リポジトリに mixin が存在しますので、これを持ち出すと良いと思います。

ent は各フィールドを固有の型にできますので、例えば上記例で ID を UserID 型にしたい場合は以下のようになります。

type UserID pulid.ID

// Fields of the User.
func (User) Fields() []ent.Field {
	return []ent.Field{
		field.String("id").
			GoType(UserID("")).
			DefaultFunc(func() UserID { return UserID(pulid.MustNew("US")) }),
		field.Int("age").Positive(),
		field.String("name").Default("unknown"),
	}
}
脚注
  1. https://github.com/tmc/pulid のように見えるのですが、こちらは Value() はバイナリを返すようです。 ↩︎

Discussion