examples/migration: add check constraint (#3873)

This commit is contained in:
Ariel Mashraki
2023-12-31 11:05:58 +02:00
committed by GitHub
parent 5755614d3f
commit e875474929
13 changed files with 229 additions and 20 deletions

View File

@@ -4,7 +4,7 @@ The full reference example for https://entgo.io/docs/versioned-migrations#create
### Migration directory
Versioned migration files exists under `ent/migrate/migrations` and follows the `golang-migrate` format.
Versioned migration files exists under `ent/migrate/migrations`.
### Changes to the Ent schema
@@ -12,18 +12,13 @@ Versioned migration files exists under `ent/migrate/migrations` and follows the
2\. Run `go generate ./ent`
### Generate new versioned migration
### Generate a new migration file
1\. Create a dev-database container if there is no one.
```shell
docker run --name migration --rm -p 3306:3306 -e MYSQL_ROOT_PASSWORD=pass -e MYSQL_DATABASE=test -d mysql
```
2\. Generate a new versioned migration file:
```go
go run -mod=mod ent/migrate/main.go <name>
```bash
atlas migrate diff <migration_name> \
--dir "file://ent/migrate/migrations" \
--to "ent://ent/schema" \
--dev-url "docker://mysql/8/ent"
```
### Run migration linting

View File

@@ -21,6 +21,8 @@ type Card struct {
config `json:"-"`
// ID of the ent.
ID int `json:"id,omitempty"`
// Number holds the value of the "number" field.
Number string `json:"number,omitempty"`
// OwnerID holds the value of the "owner_id" field.
OwnerID int `json:"owner_id,omitempty"`
// Edges holds the relations/edges for other nodes in the graph.
@@ -58,6 +60,8 @@ func (*Card) scanValues(columns []string) ([]any, error) {
switch columns[i] {
case card.FieldID, card.FieldOwnerID:
values[i] = new(sql.NullInt64)
case card.FieldNumber:
values[i] = new(sql.NullString)
default:
values[i] = new(sql.UnknownType)
}
@@ -79,6 +83,12 @@ func (c *Card) assignValues(columns []string, values []any) error {
return fmt.Errorf("unexpected type %T for field id", value)
}
c.ID = int(value.Int64)
case card.FieldNumber:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field number", values[i])
} else if value.Valid {
c.Number = value.String
}
case card.FieldOwnerID:
if value, ok := values[i].(*sql.NullInt64); !ok {
return fmt.Errorf("unexpected type %T for field owner_id", values[i])
@@ -126,6 +136,9 @@ func (c *Card) String() string {
var builder strings.Builder
builder.WriteString("Card(")
builder.WriteString(fmt.Sprintf("id=%v, ", c.ID))
builder.WriteString("number=")
builder.WriteString(c.Number)
builder.WriteString(", ")
builder.WriteString("owner_id=")
builder.WriteString(fmt.Sprintf("%v", c.OwnerID))
builder.WriteByte(')')

View File

@@ -16,6 +16,8 @@ const (
Label = "card"
// FieldID holds the string denoting the id field in the database.
FieldID = "id"
// FieldNumber holds the string denoting the number field in the database.
FieldNumber = "number"
// FieldOwnerID holds the string denoting the owner_id field in the database.
FieldOwnerID = "owner_id"
// EdgeOwner holds the string denoting the owner edge name in mutations.
@@ -34,6 +36,7 @@ const (
// Columns holds all SQL columns for card fields.
var Columns = []string{
FieldID,
FieldNumber,
FieldOwnerID,
}
@@ -60,6 +63,11 @@ func ByID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldID, opts...).ToFunc()
}
// ByNumber orders the results by the number field.
func ByNumber(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldNumber, opts...).ToFunc()
}
// ByOwnerID orders the results by the owner_id field.
func ByOwnerID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldOwnerID, opts...).ToFunc()

View File

@@ -57,11 +57,81 @@ func IDLTE(id int) predicate.Card {
return predicate.Card(sql.FieldLTE(FieldID, id))
}
// Number applies equality check predicate on the "number" field. It's identical to NumberEQ.
func Number(v string) predicate.Card {
return predicate.Card(sql.FieldEQ(FieldNumber, v))
}
// OwnerID applies equality check predicate on the "owner_id" field. It's identical to OwnerIDEQ.
func OwnerID(v int) predicate.Card {
return predicate.Card(sql.FieldEQ(FieldOwnerID, v))
}
// NumberEQ applies the EQ predicate on the "number" field.
func NumberEQ(v string) predicate.Card {
return predicate.Card(sql.FieldEQ(FieldNumber, v))
}
// NumberNEQ applies the NEQ predicate on the "number" field.
func NumberNEQ(v string) predicate.Card {
return predicate.Card(sql.FieldNEQ(FieldNumber, v))
}
// NumberIn applies the In predicate on the "number" field.
func NumberIn(vs ...string) predicate.Card {
return predicate.Card(sql.FieldIn(FieldNumber, vs...))
}
// NumberNotIn applies the NotIn predicate on the "number" field.
func NumberNotIn(vs ...string) predicate.Card {
return predicate.Card(sql.FieldNotIn(FieldNumber, vs...))
}
// NumberGT applies the GT predicate on the "number" field.
func NumberGT(v string) predicate.Card {
return predicate.Card(sql.FieldGT(FieldNumber, v))
}
// NumberGTE applies the GTE predicate on the "number" field.
func NumberGTE(v string) predicate.Card {
return predicate.Card(sql.FieldGTE(FieldNumber, v))
}
// NumberLT applies the LT predicate on the "number" field.
func NumberLT(v string) predicate.Card {
return predicate.Card(sql.FieldLT(FieldNumber, v))
}
// NumberLTE applies the LTE predicate on the "number" field.
func NumberLTE(v string) predicate.Card {
return predicate.Card(sql.FieldLTE(FieldNumber, v))
}
// NumberContains applies the Contains predicate on the "number" field.
func NumberContains(v string) predicate.Card {
return predicate.Card(sql.FieldContains(FieldNumber, v))
}
// NumberHasPrefix applies the HasPrefix predicate on the "number" field.
func NumberHasPrefix(v string) predicate.Card {
return predicate.Card(sql.FieldHasPrefix(FieldNumber, v))
}
// NumberHasSuffix applies the HasSuffix predicate on the "number" field.
func NumberHasSuffix(v string) predicate.Card {
return predicate.Card(sql.FieldHasSuffix(FieldNumber, v))
}
// NumberEqualFold applies the EqualFold predicate on the "number" field.
func NumberEqualFold(v string) predicate.Card {
return predicate.Card(sql.FieldEqualFold(FieldNumber, v))
}
// NumberContainsFold applies the ContainsFold predicate on the "number" field.
func NumberContainsFold(v string) predicate.Card {
return predicate.Card(sql.FieldContainsFold(FieldNumber, v))
}
// OwnerIDEQ applies the EQ predicate on the "owner_id" field.
func OwnerIDEQ(v int) predicate.Card {
return predicate.Card(sql.FieldEQ(FieldOwnerID, v))

View File

@@ -24,6 +24,12 @@ type CardCreate struct {
hooks []Hook
}
// SetNumber sets the "number" field.
func (cc *CardCreate) SetNumber(s string) *CardCreate {
cc.mutation.SetNumber(s)
return cc
}
// SetOwnerID sets the "owner_id" field.
func (cc *CardCreate) SetOwnerID(i int) *CardCreate {
cc.mutation.SetOwnerID(i)
@@ -86,6 +92,9 @@ func (cc *CardCreate) defaults() {
// check runs all checks and user-defined validators on the builder.
func (cc *CardCreate) check() error {
if _, ok := cc.mutation.Number(); !ok {
return &ValidationError{Name: "number", err: errors.New(`ent: missing required field "Card.number"`)}
}
if _, ok := cc.mutation.OwnerID(); !ok {
return &ValidationError{Name: "owner_id", err: errors.New(`ent: missing required field "Card.owner_id"`)}
}
@@ -118,6 +127,10 @@ func (cc *CardCreate) createSpec() (*Card, *sqlgraph.CreateSpec) {
_node = &Card{config: cc.config}
_spec = sqlgraph.NewCreateSpec(card.Table, sqlgraph.NewFieldSpec(card.FieldID, field.TypeInt))
)
if value, ok := cc.mutation.Number(); ok {
_spec.SetField(card.FieldNumber, field.TypeString, value)
_node.Number = value
}
if nodes := cc.mutation.OwnerIDs(); len(nodes) > 0 {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,

View File

@@ -301,12 +301,12 @@ func (cq *CardQuery) WithOwner(opts ...func(*UserQuery)) *CardQuery {
// Example:
//
// var v []struct {
// OwnerID int `json:"owner_id,omitempty"`
// Number string `json:"number,omitempty"`
// Count int `json:"count,omitempty"`
// }
//
// client.Card.Query().
// GroupBy(card.FieldOwnerID).
// GroupBy(card.FieldNumber).
// Aggregate(ent.Count()).
// Scan(ctx, &v)
func (cq *CardQuery) GroupBy(field string, fields ...string) *CardGroupBy {
@@ -324,11 +324,11 @@ func (cq *CardQuery) GroupBy(field string, fields ...string) *CardGroupBy {
// Example:
//
// var v []struct {
// OwnerID int `json:"owner_id,omitempty"`
// Number string `json:"number,omitempty"`
// }
//
// client.Card.Query().
// Select(card.FieldOwnerID).
// Select(card.FieldNumber).
// Scan(ctx, &v)
func (cq *CardQuery) Select(fields ...string) *CardSelect {
cq.ctx.Fields = append(cq.ctx.Fields, fields...)

View File

@@ -32,6 +32,20 @@ func (cu *CardUpdate) Where(ps ...predicate.Card) *CardUpdate {
return cu
}
// SetNumber sets the "number" field.
func (cu *CardUpdate) SetNumber(s string) *CardUpdate {
cu.mutation.SetNumber(s)
return cu
}
// SetNillableNumber sets the "number" field if the given value is not nil.
func (cu *CardUpdate) SetNillableNumber(s *string) *CardUpdate {
if s != nil {
cu.SetNumber(*s)
}
return cu
}
// SetOwnerID sets the "owner_id" field.
func (cu *CardUpdate) SetOwnerID(i int) *CardUpdate {
cu.mutation.SetOwnerID(i)
@@ -109,6 +123,9 @@ func (cu *CardUpdate) sqlSave(ctx context.Context) (n int, err error) {
}
}
}
if value, ok := cu.mutation.Number(); ok {
_spec.SetField(card.FieldNumber, field.TypeString, value)
}
if cu.mutation.OwnerCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,
@@ -158,6 +175,20 @@ type CardUpdateOne struct {
mutation *CardMutation
}
// SetNumber sets the "number" field.
func (cuo *CardUpdateOne) SetNumber(s string) *CardUpdateOne {
cuo.mutation.SetNumber(s)
return cuo
}
// SetNillableNumber sets the "number" field if the given value is not nil.
func (cuo *CardUpdateOne) SetNillableNumber(s *string) *CardUpdateOne {
if s != nil {
cuo.SetNumber(*s)
}
return cuo
}
// SetOwnerID sets the "owner_id" field.
func (cuo *CardUpdateOne) SetOwnerID(i int) *CardUpdateOne {
cuo.mutation.SetOwnerID(i)
@@ -265,6 +296,9 @@ func (cuo *CardUpdateOne) sqlSave(ctx context.Context) (_node *Card, err error)
}
}
}
if value, ok := cuo.mutation.Number(); ok {
_spec.SetField(card.FieldNumber, field.TypeString, value)
}
if cuo.mutation.OwnerCleared() {
edge := &sqlgraph.EdgeSpec{
Rel: sqlgraph.M2O,

View File

@@ -0,0 +1,2 @@
-- Modify "cards" table
ALTER TABLE `cards` ADD CONSTRAINT `number_length` CHECK (length(`number`) = 16), ADD COLUMN `number` varchar(255) NOT NULL;

View File

@@ -1,7 +1,8 @@
h1:dBIn+W0ZAQmhPheuFiVRWYhmEYxdafqorhKd8xJfKT4=
h1:JP30B60y6NKcgfLaNrIknyL1n90MwyPx5CRYGzFnBLU=
20221114082343_create_users.sql h1:EeOPKbOeYUHO830P1MCXKUsxT3wLk/hSgcpT9GzlGZQ=
20221114090322_add_age.sql h1:weRCTqS5cqKyrvIjGXk7Bn24YUXo0nhLNWD0EZBcaoQ=
20221114101516_add_name.sql h1:leQgI2JN3URZyujlNzX3gI53MSiTA02MKI/G9cnMu6I=
20221126173531_add_user_tags.sql h1:9yq4x41NnP8gqBg3IUbHKwE7gP/23Mx3ylf5IorLoFs=
20221126185750_backfill_user_tags.sql h1:qBPBJD4ry+uwj1eGPmTr5COJwv8Sjo2o+OR7TWFj6qs=
20230101214930_default_values.sql h1:W07mGRkz22lrW0dvcChRtRc5b03Kp2CsFAQZvsnb8qs=
20231231083716_add_card_number.sql h1:sBxY6RlbqEsE8hx6Q/hSuNXfBGvVmZ0OYiZcP8uDNOc=

View File

@@ -16,6 +16,7 @@ var (
// CardsColumns holds the columns for the "cards" table.
CardsColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt, Increment: true},
{Name: "number", Type: field.TypeString},
{Name: "owner_id", Type: field.TypeInt, Default: 0},
}
// CardsTable holds the schema information for the "cards" table.
@@ -26,7 +27,7 @@ var (
ForeignKeys: []*schema.ForeignKey{
{
Symbol: "cards_users_cards",
Columns: []*schema.Column{CardsColumns[1]},
Columns: []*schema.Column{CardsColumns[2]},
RefColumns: []*schema.Column{UsersColumns[0]},
OnDelete: schema.NoAction,
},
@@ -81,6 +82,10 @@ var (
func init() {
CardsTable.ForeignKeys[0].RefTable = UsersTable
CardsTable.Annotation = &entsql.Annotation{}
CardsTable.Annotation.Checks = map[string]string{
"number_length": "(LENGTH(`number`) = 16)",
}
PetsTable.ForeignKeys[0].RefTable = PetsTable
PetsTable.ForeignKeys[1].RefTable = UsersTable
UsersTable.Annotation = &entsql.Annotation{

View File

@@ -41,6 +41,7 @@ type CardMutation struct {
op Op
typ string
id *int
number *string
clearedFields map[string]struct{}
owner *int
clearedowner bool
@@ -147,6 +148,42 @@ func (m *CardMutation) IDs(ctx context.Context) ([]int, error) {
}
}
// SetNumber sets the "number" field.
func (m *CardMutation) SetNumber(s string) {
m.number = &s
}
// Number returns the value of the "number" field in the mutation.
func (m *CardMutation) Number() (r string, exists bool) {
v := m.number
if v == nil {
return
}
return *v, true
}
// OldNumber returns the old "number" field's value of the Card entity.
// If the Card object wasn't provided to the builder, the object is fetched from the database.
// An error is returned if the mutation operation is not UpdateOne, or the database query fails.
func (m *CardMutation) OldNumber(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldNumber is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldNumber requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldNumber: %w", err)
}
return oldValue.Number, nil
}
// ResetNumber resets all changes to the "number" field.
func (m *CardMutation) ResetNumber() {
m.number = nil
}
// SetOwnerID sets the "owner_id" field.
func (m *CardMutation) SetOwnerID(i int) {
m.owner = &i
@@ -244,7 +281,10 @@ func (m *CardMutation) Type() string {
// order to get all numeric fields that were incremented/decremented, call
// AddedFields().
func (m *CardMutation) Fields() []string {
fields := make([]string, 0, 1)
fields := make([]string, 0, 2)
if m.number != nil {
fields = append(fields, card.FieldNumber)
}
if m.owner != nil {
fields = append(fields, card.FieldOwnerID)
}
@@ -256,6 +296,8 @@ func (m *CardMutation) Fields() []string {
// schema.
func (m *CardMutation) Field(name string) (ent.Value, bool) {
switch name {
case card.FieldNumber:
return m.Number()
case card.FieldOwnerID:
return m.OwnerID()
}
@@ -267,6 +309,8 @@ func (m *CardMutation) Field(name string) (ent.Value, bool) {
// database failed.
func (m *CardMutation) OldField(ctx context.Context, name string) (ent.Value, error) {
switch name {
case card.FieldNumber:
return m.OldNumber(ctx)
case card.FieldOwnerID:
return m.OldOwnerID(ctx)
}
@@ -278,6 +322,13 @@ func (m *CardMutation) OldField(ctx context.Context, name string) (ent.Value, er
// type.
func (m *CardMutation) SetField(name string, value ent.Value) error {
switch name {
case card.FieldNumber:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetNumber(v)
return nil
case card.FieldOwnerID:
v, ok := value.(int)
if !ok {
@@ -337,6 +388,9 @@ func (m *CardMutation) ClearField(name string) error {
// It returns an error if the field is not defined in the schema.
func (m *CardMutation) ResetField(name string) error {
switch name {
case card.FieldNumber:
m.ResetNumber()
return nil
case card.FieldOwnerID:
m.ResetOwnerID()
return nil

View File

@@ -20,7 +20,7 @@ func init() {
cardFields := schema.Card{}.Fields()
_ = cardFields
// cardDescOwnerID is the schema descriptor for owner_id field.
cardDescOwnerID := cardFields[0].Descriptor()
cardDescOwnerID := cardFields[1].Descriptor()
// card.DefaultOwnerID holds the default value on creation for the owner_id field.
card.DefaultOwnerID = cardDescOwnerID.Default.(int)
petFields := schema.Pet{}.Fields()

View File

@@ -6,6 +6,8 @@ package schema
import (
"entgo.io/ent"
"entgo.io/ent/dialect/entsql"
"entgo.io/ent/schema"
"entgo.io/ent/schema/edge"
"entgo.io/ent/schema/field"
)
@@ -18,6 +20,7 @@ type Card struct {
// Fields of the Card.
func (Card) Fields() []ent.Field {
return []ent.Field{
field.String("number"),
field.Int("owner_id").
Default(0),
}
@@ -33,3 +36,14 @@ func (Card) Edges() []ent.Edge {
Field("owner_id"),
}
}
// Annotations of the Card.
func (Card) Annotations() []schema.Annotation {
return []schema.Annotation{
// Named check constraints are compared by their name.
// Thus, the definition does not need to be normalized.
entsql.Checks(map[string]string{
"number_length": "(LENGTH(`number`) = 16)",
}),
}
}