mirror of
https://github.com/ent/ent.git
synced 2026-04-28 21:50:56 +03:00
259 lines
6.4 KiB
Markdown
Executable File
259 lines
6.4 KiB
Markdown
Executable File
---
|
|
id: migrate
|
|
title: Database Migration
|
|
---
|
|
|
|
The migration support for `ent` provides the option for keeping the database schema
|
|
aligned with the schema objects defined in `ent/migrate/schema.go` under the root of your project.
|
|
|
|
## Auto Migration
|
|
|
|
Run the auto-migration logic in the initialization of the application:
|
|
|
|
```go
|
|
if err := client.Schema.Create(ctx); err != nil {
|
|
log.Fatalf("failed creating schema resources: %v", err)
|
|
}
|
|
```
|
|
|
|
`Create` creates all database resources needed for your `ent` project. By default, `Create` works
|
|
in an *"append-only"* mode; which means, it only creates new tables and indexes, appends columns to tables or
|
|
extends column types. For example, changing `int` to `bigint`.
|
|
|
|
What about dropping columns or indexes?
|
|
|
|
## Drop Resources
|
|
|
|
`WithDropIndex` and `WithDropColumn` are 2 options for dropping table columns and indexes.
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
|
|
"<project>/ent"
|
|
"<project>/ent/migrate"
|
|
)
|
|
|
|
func main() {
|
|
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
|
|
if err != nil {
|
|
log.Fatalf("failed connecting to mysql: %v", err)
|
|
}
|
|
defer client.Close()
|
|
ctx := context.Background()
|
|
// Run migration.
|
|
err = client.Schema.Create(
|
|
ctx,
|
|
migrate.WithDropIndex(true),
|
|
migrate.WithDropColumn(true),
|
|
)
|
|
if err != nil {
|
|
log.Fatalf("failed creating schema resources: %v", err)
|
|
}
|
|
}
|
|
```
|
|
|
|
In order to run the migration in debug mode (printing all SQL queries), run:
|
|
|
|
```go
|
|
err := client.Debug().Schema.Create(
|
|
ctx,
|
|
migrate.WithDropIndex(true),
|
|
migrate.WithDropColumn(true),
|
|
)
|
|
if err != nil {
|
|
log.Fatalf("failed creating schema resources: %v", err)
|
|
}
|
|
```
|
|
|
|
## Universal IDs
|
|
|
|
By default, SQL primary-keys start from 1 for each table; which means that multiple entities of different types
|
|
can share the same ID. Unlike AWS Neptune, where node IDs are UUIDs.
|
|
|
|
This does not work well if you work with [GraphQL](https://graphql.org/learn/schema/#scalar-types), which requires
|
|
the object ID to be unique.
|
|
|
|
To enable the Universal-IDs support for your project, pass the `WithGlobalUniqueID` option to the migration.
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
|
|
"<project>/ent"
|
|
"<project>/ent/migrate"
|
|
)
|
|
|
|
func main() {
|
|
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
|
|
if err != nil {
|
|
log.Fatalf("failed connecting to mysql: %v", err)
|
|
}
|
|
defer client.Close()
|
|
ctx := context.Background()
|
|
// Run migration.
|
|
if err := client.Schema.Create(ctx, migrate.WithGlobalUniqueID(true)); err != nil {
|
|
log.Fatalf("failed creating schema resources: %v", err)
|
|
}
|
|
}
|
|
```
|
|
|
|
**How does it work?** `ent` migration allocates a 1<<32 range for the IDs of each entity (table),
|
|
and store this information in a table named `ent_types`. For example, type `A` will have the range
|
|
of `[1,4294967296)` for its IDs, and type `B` will have the range of `[4294967296,8589934592)`, etc.
|
|
|
|
Note that if this option is enabled, the maximum number of possible tables is **65535**.
|
|
|
|
## Offline Mode
|
|
|
|
Offline mode allows you to write the schema changes to an `io.Writer` before executing them on the database.
|
|
It's useful for verifying the SQL commands before they're executed on the database, or to get an SQL script
|
|
to run manually.
|
|
|
|
**Print changes**
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"os"
|
|
|
|
"<project>/ent"
|
|
"<project>/ent/migrate"
|
|
)
|
|
|
|
func main() {
|
|
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
|
|
if err != nil {
|
|
log.Fatalf("failed connecting to mysql: %v", err)
|
|
}
|
|
defer client.Close()
|
|
ctx := context.Background()
|
|
// Dump migration changes to stdout.
|
|
if err := client.Schema.WriteTo(ctx, os.Stdout); err != nil {
|
|
log.Fatalf("failed printing schema changes: %v", err)
|
|
}
|
|
}
|
|
```
|
|
|
|
**Write changes to a file**
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"os"
|
|
|
|
"<project>/ent"
|
|
"<project>/ent/migrate"
|
|
)
|
|
|
|
func main() {
|
|
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
|
|
if err != nil {
|
|
log.Fatalf("failed connecting to mysql: %v", err)
|
|
}
|
|
defer client.Close()
|
|
ctx := context.Background()
|
|
// Dump migration changes to an SQL script.
|
|
f, err := os.Create("migrate.sql")
|
|
if err != nil {
|
|
log.Fatalf("create migrate file: %v", err)
|
|
}
|
|
defer f.Close()
|
|
if err := client.Schema.WriteTo(ctx, f); err != nil {
|
|
log.Fatalf("failed printing schema changes: %v", err)
|
|
}
|
|
}
|
|
```
|
|
|
|
## Foreign Keys
|
|
|
|
By default, `ent` uses foreign-keys when defining relationships (edges) to enforce correctness and consistency on the
|
|
database side.
|
|
|
|
However, `ent` also provide an option to disable this functionality using the `WithForeignKeys` option.
|
|
You should note that setting this option to `false`, will tell the migration to not create foreign-keys in the
|
|
schema DDL and the edges validation and clearing must be handled manually by the developer.
|
|
|
|
We expect to provide a set of hooks for implementing the foreign-key constraints in the application level in the near future.
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
|
|
"<project>/ent"
|
|
"<project>/ent/migrate"
|
|
)
|
|
|
|
func main() {
|
|
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
|
|
if err != nil {
|
|
log.Fatalf("failed connecting to mysql: %v", err)
|
|
}
|
|
defer client.Close()
|
|
ctx := context.Background()
|
|
// Run migration.
|
|
err = client.Schema.Create(
|
|
ctx,
|
|
migrate.WithForeignKeys(false), // Disable foreign keys.
|
|
)
|
|
if err != nil {
|
|
log.Fatalf("failed creating schema resources: %v", err)
|
|
}
|
|
}
|
|
```
|
|
|
|
## Migration Hooks
|
|
|
|
The framework provides an option to add hooks (middlewares) to the migration phase.
|
|
This option is ideal for modifying or filtering the tables that the migration is working on,
|
|
or for creating custom resources in the database.
|
|
|
|
```go
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
|
|
"<project>/ent"
|
|
"<project>/ent/migrate"
|
|
|
|
"entgo.io/ent/dialect/sql/schema"
|
|
)
|
|
|
|
func main() {
|
|
client, err := ent.Open("mysql", "root:pass@tcp(localhost:3306)/test")
|
|
if err != nil {
|
|
log.Fatalf("failed connecting to mysql: %v", err)
|
|
}
|
|
defer client.Close()
|
|
ctx := context.Background()
|
|
// Run migration.
|
|
err = client.Schema.Create(
|
|
ctx,
|
|
schema.WithHooks(func(next schema.Creator) schema.Creator {
|
|
return schema.CreateFunc(func(ctx context.Context, tables ...*schema.Table) error {
|
|
// Run custom code here.
|
|
return next.Create(ctx, tables...)
|
|
})
|
|
}),
|
|
)
|
|
if err != nil {
|
|
log.Fatalf("failed creating schema resources: %v", err)
|
|
}
|
|
}
|
|
```
|