snapshot of https://github.com/ent/ent.git (master, 2026-09-15; blobs > 131072B omitted)
Some checks failed
Atlas CI Public / lint (push) Failing after 13s
Atlas CI Public / sync (push) Has been skipped

This commit is contained in:
upstream-mirror
2026-09-15 22:12:36 +05:00
commit 4b3ad0b611
2680 changed files with 719472 additions and 0 deletions

View File

@@ -0,0 +1,241 @@
---
title: Using Composite Types in Ent Schema
id: composite
slug: composite-types
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import InstallationInstructions from '../components/_installation_instructions.mdx';
In PostgreSQL, a composite type is structured like a row or record, consisting of field names and their corresponding
data types. Setting an Ent field as a composite type enables you to store complex and structured data in a single column.
This guide explains how to define a schema field type as a composite type in your Ent schema and configure the schema migration
to manage both the composite types and the Ent schema as a single migration unit using Atlas.
:::info [Atlas Pro Feature](https://atlasgo.io/features#pro-plan)
Atlas support for [Composite Types](https://atlasgo.io/atlas-schema/hcl#composite-type) is available exclusively to Pro users.
To use this feature, run:
```
atlas login
```
:::
## Install Atlas
<InstallationInstructions />
## Login to Atlas
```shell
$ atlas login a8m
//highlight-next-line-info
You are now connected to "a8m" on Atlas Cloud.
```
## Composite Schema
An `ent/schema` package is mostly used for defining Ent types (objects), their fields, edges and logic. Composite types,
or any other database objects do not have representation in Ent models - A composite type can be defined once,
and may be used multiple times in different fields and models.
In order to extend our PostgreSQL schema to include both custom composite types and our Ent types, we configure Atlas to
read the state of the schema from a [Composite Schema](https://atlasgo.io/atlas-schema/projects#data-source-composite_schema)
data source. Follow the steps below to configure this for your project:
1\. Create a `schema.sql` that defines the necessary composite type. In the same way, you can configure the composite type in
[Atlas Schema HCL language](https://atlasgo.io/atlas-schema/hcl-types#composite-type):
<Tabs>
<TabItem value={"sql"} label={"Using SQL"}>
```sql title="schema.sql"
CREATE TYPE address AS (
street text,
city text
);
```
</TabItem>
<TabItem value={"hcl"} label={"Using HCL"}>
```hcl title="schema.hcl"
schema "public" {}
composite "address" {
schema = schema.public
field "street" {
type = text
}
field "city" {
type = text
}
}
```
</TabItem>
</Tabs>
2\. In your Ent schema, define a field that uses the composite type only in PostgreSQL dialect:
<Tabs>
<TabItem value={"schema"} label={"Schema"}>
```go title="ent/schema/user.go" {6-8}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("address").
GoType(&Address{}).
SchemaType(map[string]string{
dialect.Postgres: "address",
}),
}
}
```
:::note
In case a schema with custom driver-specific types is used with other databases, Ent falls back to the default type
used by the driver (e.g., "varchar").
:::
</TabItem>
<TabItem value={"address"} label={"Address Type"}>
```go title="ent/schematype/address.go"
type Address struct {
Street, City string
}
var _ field.ValueScanner = (*Address)(nil)
// Scan implements the database/sql.Scanner interface.
func (a *Address) Scan(v interface{}) (err error) {
switch v := v.(type) {
case nil:
case string:
_, err = fmt.Sscanf(v, "(%q,%q)", &a.Street, &a.City)
case []byte:
_, err = fmt.Sscanf(string(v), "(%q,%q)", &a.Street, &a.City)
}
return
}
// Value implements the driver.Valuer interface.
func (a *Address) Value() (driver.Value, error) {
return fmt.Sprintf("(%q,%q)", a.Street, a.City), nil
}
```
</TabItem>
</Tabs>
3\. Create a simple `atlas.hcl` config file with a `composite_schema` that includes both your custom types defined in
`schema.sql` and your Ent schema:
```hcl title="atlas.hcl"
data "composite_schema" "app" {
# Load first custom types first.
schema "public" {
url = "file://schema.sql"
}
# Second, load the Ent schema.
schema "public" {
url = "ent://ent/schema"
}
}
env "local" {
src = data.composite_schema.app.url
dev = "docker://postgres/15/dev?search_path=public"
}
```
## Usage
After setting up our schema, we can get its representation using the `atlas schema inspect` command, generate migrations for
it, apply them to a database, and more. Below are a few commands to get you started with Atlas:
#### Inspect the Schema
The `atlas schema inspect` command is commonly used to inspect databases. However, we can also use it to inspect our
`composite_schema` and print the SQL representation of it:
```shell
atlas schema inspect \
--env local \
--url env://src \
--format '{{ sql . }}'
```
The command above prints the following SQL. Note, the `address` composite type is defined in the schema before
its usage in the `address` field:
```sql
-- Create composite type "address"
CREATE TYPE "address" AS ("street" text, "city" text);
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "address" "address" NOT NULL, PRIMARY KEY ("id"));
```
#### Generate Migrations For the Schema
To generate a migration for the schema, run the following command:
```shell
atlas migrate diff \
--env local
```
Note that a new migration file is created with the following content:
```sql title="migrations/20240712090543.sql"
-- Create composite type "address"
CREATE TYPE "address" AS ("street" text, "city" text);
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "address" "address" NOT NULL, PRIMARY KEY ("id"));
```
#### Apply the Migrations
To apply the migration generated above to a database, run the following command:
```
atlas migrate apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
```
:::info Apply the Schema Directly on the Database
Sometimes, there is a need to apply the schema directly to the database without generating a migration file. For example,
when experimenting with schema changes, spinning up a database for testing, etc. In such cases, you can use the command
below to apply the schema directly to the database:
```shell
atlas schema apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
```
Or, using the [Atlas Go SDK](https://github.com/ariga/atlas-go-sdk):
```go
ac, err := atlasexec.NewClient(".", "atlas")
if err != nil {
log.Fatalf("failed to initialize client: %w", err)
}
// Automatically update the database with the desired schema.
// Another option, is to use 'migrate apply' or 'schema apply' manually.
if _, err := ac.SchemaApply(ctx, &atlasexec.SchemaApplyParams{
Env: "local",
URL: "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable",
AutoApprove: true,
}); err != nil {
log.Fatalf("failed to apply schema changes: %w", err)
}
```
:::
The code for this guide can be found in [GitHub](https://github.com/ent/ent/tree/master/examples/compositetypes).

208
doc/md/migration/domain.mdx Normal file
View File

@@ -0,0 +1,208 @@
---
title: Using Domain Types in Ent Schema
id: domain
slug: domain-types
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import InstallationInstructions from '../components/_installation_instructions.mdx';
PostgreSQL domain types are user-defined data types that extend existing ones, allowing you to add constraints that
restrict the values they can hold. Setting a field type as a domain type enables you to enforce data integrity and
validation rules at the database level.
This guide explains how to define a schema field type as a domain type in your Ent schema and configure the schema migration
to manage both the domains and the Ent schema as a single migration unit using Atlas.
:::info [Atlas Pro Feature](https://atlasgo.io/features#pro-plan)
Atlas support for [Domain Types](https://atlasgo.io/atlas-schema/hcl#domain) is available exclusively to Pro users.
To use this feature, run:
```
atlas login
```
:::
## Install Atlas
<InstallationInstructions />
## Login to Atlas
```shell
$ atlas login a8m
//highlight-next-line-info
You are now connected to "a8m" on Atlas Cloud.
```
## Composite Schema
An `ent/schema` package is mostly used for defining Ent types (objects), their fields, edges and logic. Domain types,
or any other database objects do not have representation in Ent models - A domain type can be defined once,
and may be used multiple times in different fields and models.
In order to extend our PostgreSQL schema to include both custom domain types and our Ent types, we configure Atlas to
read the state of the schema from a [Composite Schema](https://atlasgo.io/atlas-schema/projects#data-source-composite_schema)
data source. Follow the steps below to configure this for your project:
1\. Create a `schema.sql` that defines the necessary domain type. In the same way, you can configure the domain type in
[Atlas Schema HCL language](https://atlasgo.io/atlas-schema/hcl-types#domain):
<Tabs>
<TabItem value={"sql"} label={"Using SQL"}>
```sql title="schema.sql"
CREATE DOMAIN us_postal_code AS TEXT
CHECK(
VALUE ~ '^\d{5}$'
OR VALUE ~ '^\d{5}-\d{4}$'
);
```
</TabItem>
<TabItem value={"hcl"} label={"Using HCL"}>
```hcl title="schema.hcl"
schema "public" {}
domain "us_postal_code" {
schema = schema.public
type = text
null = true
check "us_postal_code_check" {
expr = "((VALUE ~ '^\\d{5}$'::text) OR (VALUE ~ '^\\d{5}-\\d{4}$'::text))"
}
}
```
</TabItem>
</Tabs>
2\. In your Ent schema, define a field that uses the domain type only in PostgreSQL dialect:
```go title="ent/schema/user.go" {5-7}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("postal_code").
SchemaType(map[string]string{
dialect.Postgres: "us_postal_code",
}),
}
}
```
:::note
In case a schema with custom driver-specific types is used with other databases, Ent falls back to the default type
used by the driver (e.g., "varchar").
:::
3\. Create a simple `atlas.hcl` config file with a `composite_schema` that includes both your custom types defined in
`schema.sql` and your Ent schema:
```hcl title="atlas.hcl"
data "composite_schema" "app" {
# Load first custom types first.
schema "public" {
url = "file://schema.sql"
}
# Second, load the Ent schema.
schema "public" {
url = "ent://ent/schema"
}
}
env "local" {
src = data.composite_schema.app.url
dev = "docker://postgres/15/dev?search_path=public"
}
```
## Usage
After setting up our schema, we can get its representation using the `atlas schema inspect` command, generate migrations for
it, apply them to a database, and more. Below are a few commands to get you started with Atlas:
#### Inspect the Schema
The `atlas schema inspect` command is commonly used to inspect databases. However, we can also use it to inspect our
`composite_schema` and print the SQL representation of it:
```shell
atlas schema inspect \
--env local \
--url env://src \
--format '{{ sql . }}'
```
The command above prints the following SQL. Note, the `us_postal_code` domain type is defined in the schema before
its usage in the `postal_code` field:
```sql
-- Create domain type "us_postal_code"
CREATE DOMAIN "us_postal_code" AS text CONSTRAINT "us_postal_code_check" CHECK ((VALUE ~ '^\d{5}$'::text) OR (VALUE ~ '^\d{5}-\d{4}$'::text));
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "postal_code" "us_postal_code" NOT NULL, PRIMARY KEY ("id"));
```
#### Generate Migrations For the Schema
To generate a migration for the schema, run the following command:
```shell
atlas migrate diff \
--env local
```
Note that a new migration file is created with the following content:
```sql title="migrations/20240712090543.sql"
-- Create domain type "us_postal_code"
CREATE DOMAIN "us_postal_code" AS text CONSTRAINT "us_postal_code_check" CHECK ((VALUE ~ '^\d{5}$'::text) OR (VALUE ~ '^\d{5}-\d{4}$'::text));
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "postal_code" "us_postal_code" NOT NULL, PRIMARY KEY ("id"));
```
#### Apply the Migrations
To apply the migration generated above to a database, run the following command:
```
atlas migrate apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
```
:::info Apply the Schema Directly on the Database
Sometimes, there is a need to apply the schema directly to the database without generating a migration file. For example,
when experimenting with schema changes, spinning up a database for testing, etc. In such cases, you can use the command
below to apply the schema directly to the database:
```shell
atlas schema apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
```
Or, using the [Atlas Go SDK](https://github.com/ariga/atlas-go-sdk):
```go
ac, err := atlasexec.NewClient(".", "atlas")
if err != nil {
log.Fatalf("failed to initialize client: %w", err)
}
// Automatically update the database with the desired schema.
// Another option, is to use 'migrate apply' or 'schema apply' manually.
if _, err := ac.SchemaApply(ctx, &atlasexec.SchemaApplyParams{
Env: "local",
URL: "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable",
AutoApprove: true,
}); err != nil {
log.Fatalf("failed to apply schema changes: %w", err)
}
```
:::
The code for this guide can be found in [GitHub](https://github.com/ent/ent/tree/master/examples/domaintypes).

202
doc/md/migration/enum.mdx Normal file
View File

@@ -0,0 +1,202 @@
---
title: Using Postgres Enum Types in Ent Schema
id: enum
slug: enum-types
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import InstallationInstructions from '../components/_installation_instructions.mdx';
Enum types are data structures that consist of a predefined, ordered set of values. By default, when using `field.Enum`
in your Ent schema, Ent uses simple string types to represent the enum values in **PostgreSQL and SQLite**. However, in some
cases, you may want to use the native enum types provided by the database.
This guide explains how to define a schema field that uses a native PostgreSQL enum type and configure the schema migration
to manage both Postgres enums and the Ent schema as a single migration unit using Atlas.
:::info [Atlas Pro Feature](https://atlasgo.io/features#pro-plan)
Atlas support for [Composite Schema](https://atlasgo.io/atlas-schema/projects#data-source-composite_schema) used in this
guide is available exclusively to Pro users. To use this feature, run:
```
atlas login
```
:::
## Install Atlas
<InstallationInstructions />
## Login to Atlas
```shell
$ atlas login a8m
//highlight-next-line-info
You are now connected to "a8m" on Atlas Cloud.
```
## Composite Schema
An `ent/schema` package is mostly used for defining Ent types (objects), their fields, edges and logic. External enum types,
or any other database objects do not have representation in Ent models - A Postgres enum type can be defined once in your Postgres
schema, and may be used multiple times in different fields and models.
In order to extend our PostgreSQL schema to include both custom enum types and our Ent types, we configure Atlas to
read the state of the schema from a [Composite Schema](https://atlasgo.io/atlas-schema/projects#data-source-composite_schema)
data source. Follow the steps below to configure this for your project:
1\. Create a `schema.sql` that defines the necessary enum type there. In the same way, you can define the enum type in
[Atlas Schema HCL language](https://atlasgo.io/atlas-schema/hcl-types#enum):
<Tabs>
<TabItem value={"sql"} label={"Using SQL"}>
```sql title="schema.sql"
CREATE TYPE status AS ENUM ('active', 'inactive', 'pending');
```
</TabItem>
<TabItem value={"hcl"} label={"Using HCL"}>
```hcl title="schema.hcl"
schema "public" {}
enum "status" {
schema = schema.public
values = ["active", "inactive", "pending"]
}
```
</TabItem>
</Tabs>
2\. In your Ent schema, define an enum field that uses the underlying Postgres `ENUM` type:
```go title="ent/schema/user.go" {6-8}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.Enum("status").
Values("active", "inactive", "pending").
SchemaType(map[string]string{
dialect.Postgres: "status",
}),
}
}
```
:::note
In case a schema with custom driver-specific types is used with other databases, Ent falls back to the default type
used by the driver (e.g., `TEXT` in SQLite and `ENUM (...)` in MariaDB or MySQL)s.
:::
3\. Create a simple `atlas.hcl` config file with a `composite_schema` that includes both your custom enum types defined in
`schema.sql` and your Ent schema:
```hcl title="atlas.hcl"
data "composite_schema" "app" {
# Load first custom types first.
schema "public" {
url = "file://schema.sql"
}
# Second, load the Ent schema.
schema "public" {
url = "ent://ent/schema"
}
}
env "local" {
src = data.composite_schema.app.url
dev = "docker://postgres/15/dev?search_path=public"
}
```
## Usage
After setting up our composite schema, we can get its representation using the `atlas schema inspect` command, generate
schema migrations for it, apply them to a database, and more. Below are a few commands to get you started with Atlas:
#### Inspect the Schema
The `atlas schema inspect` command is commonly used to inspect databases. However, we can also use it to inspect our
`composite_schema` and print the SQL representation of it:
```shell
atlas schema inspect \
--env local \
--url env://src \
--format '{{ sql . }}'
```
The command above prints the following SQL. Note, the `status` enum type is defined in the schema before
its usage in the `users.status` column:
```sql
-- Create enum type "status"
CREATE TYPE "status" AS ENUM ('active', 'inactive', 'pending');
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "status" "status" NOT NULL, PRIMARY KEY ("id"));
```
#### Generate Migrations For the Schema
To generate a migration for the schema, run the following command:
```shell
atlas migrate diff \
--env local
```
Note that a new migration file is created with the following content:
```sql title="migrations/20240712090543.sql"
-- Create enum type "status"
CREATE TYPE "status" AS ENUM ('active', 'inactive', 'pending');
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "status" "status" NOT NULL, PRIMARY KEY ("id"));
```
#### Apply the Migrations
To apply the migration generated above to a database, run the following command:
```
atlas migrate apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
```
:::info Apply the Schema Directly on the Database
Sometimes, there is a need to apply the schema directly to the database without generating a migration file. For example,
when experimenting with schema changes, spinning up a database for testing, etc. In such cases, you can use the command
below to apply the schema directly to the database:
```shell
atlas schema apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
```
Or, using the [Atlas Go SDK](https://github.com/ariga/atlas-go-sdk):
```go
ac, err := atlasexec.NewClient(".", "atlas")
if err != nil {
log.Fatalf("failed to initialize client: %w", err)
}
// Automatically update the database with the desired schema.
// Another option, is to use 'migrate apply' or 'schema apply' manually.
if _, err := ac.SchemaApply(ctx, &atlasexec.SchemaApplyParams{
Env: "local",
URL: "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable",
AutoApprove: true,
}); err != nil {
log.Fatalf("failed to apply schema changes: %w", err)
}
```
:::
The code for this guide can be found in [GitHub](https://github.com/ent/ent/tree/master/examples/enumtypes).

View File

@@ -0,0 +1,223 @@
---
title: Using Postgres Extensions in Ent Schema
id: extension
slug: extensions
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import InstallationInstructions from '../components/_installation_instructions.mdx';
[Postgres extensions](https://www.postgresql.org/docs/current/sql-createextension.html) are add-on modules that extend
the functionality of the database by providing new data types, operators, functions, procedural languages, and more.
This guide explains how to define a schema field that uses a data type provided by the PostGIS extension, and configure
the schema migration to manage both Postgres extension installations and the Ent schema as a single migration unit using
Atlas.
:::info [Atlas Pro Feature](https://atlasgo.io/features#pro-plan)
Atlas support for [Extensions](https://atlasgo.io/atlas-schema/hcl#extension) is available exclusively to Pro users.
To use this feature, run:
```
atlas login
```
:::
## Install Atlas
<InstallationInstructions />
## Login to Atlas
```shell
$ atlas login a8m
//highlight-next-line-info
You are now connected to "a8m" on Atlas Cloud.
```
## Composite Schema
An `ent/schema` package is mostly used for defining Ent types (objects), their fields, edges and logic. Extensions like
`postgis` or `hstore` do not have representation in Ent schema. A Postgres extension can be installed once in your
Postgres database, and may be used multiple times in different schemas.
In order to extend our PostgreSQL schema migration to include both extensions and our Ent types, we configure Atlas to
read the state of the schema from a [Composite Schema](https://atlasgo.io/atlas-schema/projects#data-source-composite_schema)
data source. Follow the steps below to configure this for your project:
1\. Create a `schema.sql` that defines the necessary extensions used by your database. In the same way, you can define
the extensions in [Atlas Schema HCL language](https://atlasgo.io/atlas-schema/hcl-types#extension):
<Tabs>
<TabItem value={"sql"} label={"Using SQL"}>
```sql title="schema.sql"
-- Install PostGIS extension.
CREATE EXTENSION postgis;
```
</TabItem>
<TabItem value={"hcl"} label={"Using HCL"}>
```hcl title="schema.hcl"
schema "public" {}
extension "postgis" {
schema = schema.public
version = "3.4.2"
comment = "PostGIS geometry and geography spatial types and functions"
}
```
</TabItem>
</Tabs>
2\. In your Ent schema, define a field that uses the data type provided by the extension. In this example, we use the
`GEOMETRY(Point, 4326)` data type provided by the `postgis` extension:
```go title="ent/schema/user.go" {7-9}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.Bytes("location").
// Ideally, we would use a custom GoType
// to represent the "geometry" type.
SchemaType(map[string]string{
dialect.Postgres: "GEOMETRY(Point, 4326)",
}),
}
}
```
3\. Create a simple `atlas.hcl` config file with a `composite_schema` that includes both the extensions defined in
`schema.sql` and your Ent schema:
```hcl title="atlas.hcl"
data "composite_schema" "app" {
# Install extensions first (PostGIS).
schema "public" {
url = "file://schema.sql"
}
# Then, load the Ent schema.
schema "public" {
url = "ent://ent/schema"
}
}
env "local" {
src = data.composite_schema.app.url
dev = "docker://postgis/latest/dev"
format {
migrate {
diff = "{{ sql . \" \" }}"
}
}
}
```
## Usage
After setting up our composite schema, we can get its representation using the `atlas schema inspect` command, generate
schema migrations for it, apply them to a database, and more. Below are a few commands to get you started with Atlas:
#### Inspect the Schema
The `atlas schema inspect` command is commonly used to inspect databases. However, we can also use it to inspect our
`composite_schema` and print the SQL representation of it:
```shell
atlas schema inspect \
--env local \
--url env://src \
--format '{{ sql . }}'
```
The command above prints the following SQL.
```sql
-- Add new schema named "public"
CREATE SCHEMA IF NOT EXISTS "public";
-- Set comment to schema: "public"
COMMENT ON SCHEMA "public" IS 'standard public schema';
-- Create extension "postgis"
CREATE EXTENSION "postgis" WITH SCHEMA "public" VERSION "3.4.2";
-- Create "users" table
CREATE TABLE "public"."users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "location" public.geometry(point,4326) NOT NULL, PRIMARY KEY ("id"));
```
:::info Extensions Are Database-Level Objects
Although the `SCHEMA` argument is supported by the `CREATE EXTENSION` command, it only indicates where the extension's
objects will be installed. The extension itself is installed at the database level and cannot be loaded multiple times
into different schemas.
Therefore, to avoid conflicts with other schemas, when working with extensions, the scope of the migration should be set
to the database, where objects are qualified with the schema name. Hence, the `search_path` is dropped from the dev-database
URL in the `atlas.hcl` file.
:::
#### Generate Migrations For the Schema
To generate a migration for the schema, run the following command:
```shell
atlas migrate diff \
--env local
```
Note that a new migration file is created with the following content:
```sql title="migrations/20240712090543.sql"
-- Create extension "postgis"
CREATE EXTENSION "postgis" WITH SCHEMA "public" VERSION "3.4.2";
-- Create "users" table
CREATE TABLE "public"."users" (
"id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
"location" public.geometry(point,4326) NOT NULL,
PRIMARY KEY ("id")
);
```
#### Apply the Migrations
To apply the migration generated above to a database, run the following command:
```
atlas migrate apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
```
:::info Apply the Schema Directly on the Database
Sometimes, there is a need to apply the schema directly to the database without generating a migration file. For example,
when experimenting with schema changes, spinning up a database for testing, etc. In such cases, you can use the command
below to apply the schema directly to the database:
```shell
atlas schema apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?sslmode=disable"
```
Or, using the [Atlas Go SDK](https://github.com/ariga/atlas-go-sdk):
```go
ac, err := atlasexec.NewClient(".", "atlas")
if err != nil {
log.Fatalf("failed to initialize client: %w", err)
}
// Automatically update the database with the desired schema.
// Another option, is to use 'migrate apply' or 'schema apply' manually.
if _, err := ac.SchemaApply(ctx, &atlasexec.SchemaApplyParams{
Env: "local",
URL: "postgres://postgres:pass@localhost:5432/database?sslmode=disable",
AutoApprove: true,
}); err != nil {
log.Fatalf("failed to apply schema changes: %w", err)
}
```
:::
The code for this guide can be found in [GitHub](https://github.com/ent/ent/tree/master/examples/enumtypes).

View File

@@ -0,0 +1,200 @@
---
title: Using Functional Indexes in Ent Schema
id: functional-indexes
slug: functional-indexes
---
import InstallationInstructions from '../components/_installation_instructions.mdx';
A functional index is an index whose key parts are based on expression values, rather than column values. This index
type is helpful for indexing the results of functions or expressions that are not stored in the table. Supported by
[MySQL, MariaDB](https://atlasgo.io/guides/mysql/functional-indexes), [PostgreSQL](https://atlasgo.io/guides/postgres/functional-indexes)
and [SQLite](https://atlasgo.io/guides/sqlite/functional-indexes).
This guide explains how to extend your Ent schema with functional indexes, and configure the schema migration to manage
both functional indexes and the Ent schema as a single migration unit using Atlas.
:::info [Atlas Pro Feature](https://atlasgo.io/features#pro-plan)
Atlas support for [Composite Schema](https://atlasgo.io/atlas-schema/projects#data-source-composite_schema) used in this
guide is available exclusively to Pro users. To use this feature, run:
```
atlas login
```
:::
## Install Atlas
<InstallationInstructions />
## Login to Atlas
```shell
$ atlas login a8m
//highlight-next-line-info
You are now connected to "a8m" on Atlas Cloud.
```
## Composite Schema
An `ent/schema` package is mostly used for defining Ent types (objects), their fields, edges and logic. Functional indexes,
do not have representation in Ent schema, as Ent supports defining indexes on fields, edges (foreign-keys), and the combination
of them.
In order to extend our PostgreSQL schema migration with functional indexes to our Ent types (tables), we configure Atlas to
read the state of the schema from a [Composite Schema](https://atlasgo.io/atlas-schema/projects#data-source-composite_schema)
data source. Follow the steps below to configure this for your project:
1\. Let's define a simple schema with one type (table): `User` (table `users`):
```go title="ent/schema/user.go"
// User holds the schema definition for the User entity.
type User struct {
ent.Schema
}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("name").
Comment("A unique index is defined on lower(name) in schema.sql"),
}
}
```
2\. Next step, we define a functional index on the `name` field in the `schema.sql` file:
```sql title="schema.sql" {2}
-- Create a functional (unique) index on the lowercased name column.
CREATE UNIQUE INDEX unique_name ON "users" ((lower("name")));
```
3\. Create a simple `atlas.hcl` config file with a `composite_schema` that includes both the functional indexes defined in
`schema.sql` and your Ent schema:
```hcl title="atlas.hcl"
data "composite_schema" "app" {
# Load the ent schema first with all tables.
schema "public" {
url = "ent://ent/schema"
}
# Then, load the functional indexes.
schema "public" {
url = "file://schema.sql"
}
}
env "local" {
src = data.composite_schema.app.url
dev = "docker://postgres/15/dev?search_path=public"
}
```
## Usage
After setting up our composite schema, we can get its representation using the `atlas schema inspect` command, generate
schema migrations for it, apply them to a database, and more. Below are a few commands to get you started with Atlas:
#### Inspect the Schema
The `atlas schema inspect` command is commonly used to inspect databases. However, we can also use it to inspect our
`composite_schema` and print the SQL representation of it:
```shell
atlas schema inspect \
--env local \
--url env://src \
--format '{{ sql . }}'
```
The command above prints the following SQL.
```sql
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" character varying NOT NULL, PRIMARY KEY ("id"));
-- Create index "unique_name" to table: "users"
CREATE UNIQUE INDEX "unique_name" ON "users" ((lower((name)::text)));
```
Note, our functional index is defined on the `name` field in the `users` table.
#### Generate Migrations For the Schema
To generate a migration for the schema, run the following command:
```shell
atlas migrate diff \
--env local
```
Note that a new migration file is created with the following content:
```sql title="migrations/20240712090543.sql"
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" character varying NOT NULL, PRIMARY KEY ("id"));
-- Create index "unique_name" to table: "users"
CREATE UNIQUE INDEX "unique_name" ON "users" ((lower((name)::text)));
```
#### Apply the Migrations
To apply the migration generated above to a database, run the following command:
```
atlas migrate apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
```
:::info Apply the Schema Directly on the Database
Sometimes, there is a need to apply the schema directly to the database without generating a migration file. For example,
when experimenting with schema changes, spinning up a database for testing, etc. In such cases, you can use the command
below to apply the schema directly to the database:
```shell
atlas schema apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?sslmode=disable"
```
Or, using the [Atlas Go SDK](https://github.com/ariga/atlas-go-sdk):
```go
ac, err := atlasexec.NewClient(".", "atlas")
if err != nil {
log.Fatalf("failed to initialize client: %w", err)
}
// Automatically update the database with the desired schema.
// Another option, is to use 'migrate apply' or 'schema apply' manually.
if _, err := ac.SchemaApply(ctx, &atlasexec.SchemaApplyParams{
Env: "local",
URL: "postgres://postgres:pass@localhost:5432/database?sslmode=disable",
AutoApprove: true,
}); err != nil {
log.Fatalf("failed to apply schema changes: %w", err)
}
```
:::
## Code Example
After setting up our Ent schema with functional indexes, we expect the database to enforce the uniqueness of the `name`
field in the `users` table:
```go
// Test that the unique index is enforced.
client.User.Create().SetName("Ariel").SaveX(ctx)
err = client.User.Create().SetName("ariel").Exec(ctx)
require.EqualError(t, err, `ent: constraint failed: pq: duplicate key value violates unique constraint "unique_name"`)
// Type-assert returned error.
var pqerr *pq.Error
require.True(t, errors.As(err, &pqerr))
require.Equal(t, `duplicate key value violates unique constraint "unique_name"`, pqerr.Message)
require.Equal(t, user.Table, pqerr.Table)
require.Equal(t, "unique_name", pqerr.Constraint)
require.Equal(t, pq.ErrorCode("23505"), pqerr.Code, "unique violation")
```
The code for this guide can be found in [GitHub](https://github.com/ent/ent/tree/master/examples/functionalidx).

227
doc/md/migration/rls.mdx Normal file
View File

@@ -0,0 +1,227 @@
---
title: Using Row-Level Security in Ent Schema
id: rls
slug: row-level-security
---
import InstallationInstructions from '../components/_installation_instructions.mdx';
Row-level security (RLS) in PostgreSQL enables tables to implement policies that limit access or modification of rows
according to the user's role, enhancing the basic SQL-standard privileges provided by `GRANT`.
Once activated, every standard access to the table has to adhere to these policies. If no policies are defined on the table,
it defaults to a deny-all rule, meaning no rows can be seen or mutated. These policies can be tailored to specific commands,
roles, or both, allowing for detailed management of who can access or change data.
This guide explains how to attach Row-Level Security (RLS) Policies to your Ent types (objects) and configure the schema
migration to manage both the RLS and the Ent schema as a single migration unit using Atlas.
:::info [Atlas Pro Feature](https://atlasgo.io/features#pro-plan)
Atlas support for [Row-Level Security Policies](https://atlasgo.io/atlas-schema/hcl#row-level-security-policy) used in
this guide is available exclusively to Pro users. To use this feature, run:
```
atlas login
```
:::
## Install Atlas
<InstallationInstructions />
## Login to Atlas
```shell
$ atlas login a8m
//highlight-next-line-info
You are now connected to "a8m" on Atlas Cloud.
```
## Composite Schema
An `ent/schema` package is mostly used for defining Ent types (objects), their fields, edges and logic. Table policies
or any other database native objects do not have representation in Ent models.
In order to extend our PostgreSQL schema to include both our Ent types and their policies, we configure Atlas to
read the state of the schema from a [Composite Schema](https://atlasgo.io/atlas-schema/projects#data-source-composite_schema)
data source. Follow the steps below to configure this for your project:
1\. Let's define a simple schema with two types (tables): `users` and `tenants`:
```go title="ent/schema/tenant.go"
// Tenant holds the schema definition for the Tenant entity.
type Tenant struct {
ent.Schema
}
// Fields of the Tenant.
func (Tenant) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
}
}
// User holds the schema definition for the User entity.
type User struct {
ent.Schema
}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
field.Int("tenant_id"),
}
}
```
2\. Now, suppose we want to limit access to the `users` table based on the `tenant_id` field. We can achieve this by defining
a Row-Level Security (RLS) policy on the `users` table. Below is the SQL code that defines the RLS policy:
```sql title="schema.sql"
--- Enable row-level security on the users table.
ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;
-- Create a policy that restricts access to rows in the users table based on the current tenant.
CREATE POLICY tenant_isolation ON "users"
USING ("tenant_id" = current_setting('app.current_tenant')::integer);
```
3\. Lastly, we create a simple `atlas.hcl` config file with a `composite_schema` that includes both our Ent schema and
the custom security policies defined in `schema.sql`:
```hcl title="atlas.hcl"
data "composite_schema" "app" {
# Load the ent schema first with all tables.
schema "public" {
url = "ent://ent/schema"
}
# Then, load the RLS schema.
schema "public" {
url = "file://schema.sql"
}
}
env "local" {
src = data.composite_schema.app.url
dev = "docker://postgres/15/dev?search_path=public"
}
```
## Usage
After setting up our composite schema, we can get its representation using the `atlas schema inspect` command, generate
schema migrations for it, apply them to a database, and more. Below are a few commands to get you started with Atlas:
#### Inspect the Schema
The `atlas schema inspect` command is commonly used to inspect databases. However, we can also use it to inspect our
`composite_schema` and print the SQL representation of it:
```shell
atlas schema inspect \
--env local \
--url env://src \
--format '{{ sql . }}'
```
The command above prints the following SQL. Note, the `tenant_isolation` policy is defined in the schema after the `users`
table:
```sql
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" character varying NOT NULL, "tenant_id" bigint NOT NULL, PRIMARY KEY ("id"));
-- Enable row-level security for "users" table
ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;
-- Create policy "tenant_isolation"
CREATE POLICY "tenant_isolation" ON "users" AS PERMISSIVE FOR ALL TO PUBLIC USING (tenant_id = (current_setting('app.current_tenant'::text))::integer);
-- Create "tenants" table
CREATE TABLE "tenants" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" character varying NOT NULL, PRIMARY KEY ("id"));
```
#### Generate Migrations For the Schema
To generate a migration for the schema, run the following command:
```shell
atlas migrate diff \
--env local
```
Note that a new migration file is created with the following content:
```sql title="migrations/20240712090543.sql"
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" character varying NOT NULL, "tenant_id" bigint NOT NULL, PRIMARY KEY ("id"));
-- Enable row-level security for "users" table
ALTER TABLE "users" ENABLE ROW LEVEL SECURITY;
-- Create policy "tenant_isolation"
CREATE POLICY "tenant_isolation" ON "users" AS PERMISSIVE FOR ALL TO PUBLIC USING (tenant_id = (current_setting('app.current_tenant'::text))::integer);
-- Create "tenants" table
CREATE TABLE "tenants" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" character varying NOT NULL, PRIMARY KEY ("id"));
```
#### Apply the Migrations
To apply the migration generated above to a database, run the following command:
```
atlas migrate apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
```
:::info Apply the Schema Directly on the Database
Sometimes, there is a need to apply the schema directly to the database without generating a migration file. For example,
when experimenting with schema changes, spinning up a database for testing, etc. In such cases, you can use the command
below to apply the schema directly to the database:
```shell
atlas schema apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
```
Or, using the [Atlas Go SDK](https://github.com/ariga/atlas-go-sdk):
```go
ac, err := atlasexec.NewClient(".", "atlas")
if err != nil {
log.Fatalf("failed to initialize client: %w", err)
}
// Automatically update the database with the desired schema.
// Another option, is to use 'migrate apply' or 'schema apply' manually.
if _, err := ac.SchemaApply(ctx, &atlasexec.SchemaApplyParams{
Env: "local",
URL: "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable",
AutoApprove: true,
}); err != nil {
log.Fatalf("failed to apply schema changes: %w", err)
}
```
:::
## Code Example
After setting up our Ent schema and the RLS policies, we can open an Ent client and pass the different mutations and
queries the relevant tenant ID we work on. This ensures that the database upholds our RLS policy:
```go
ctx1, ctx2 := sql.WithIntVar(ctx, "app.current_tenant", a8m.ID), sql.WithIntVar(ctx, "app.current_tenant", r3m.ID)
users1 := client.User.Query().AllX(ctx1)
// Users1 can only see users from tenant a8m.
users2 := client.User.Query().AllX(ctx2)
// Users2 can only see users from tenant r3m.
```
:::info Real World Example
In real applications, users can utilize [hooks](/docs/hooks) and [interceptors](/docs/interceptors) to set the `app.current_tenant`
variable based on the user's context.
:::
The code for this guide can be found in [GitHub](https://github.com/ent/ent/tree/master/examples/rls).

View File

@@ -0,0 +1,277 @@
---
title: Using Database Triggers in Ent Schema
id: trigger
slug: triggers
---
import InstallationInstructions from '../components/_installation_instructions.mdx';
Triggers are useful tools in relational databases that allow you to execute custom code when specific events occur on a
table. For instance, triggers can automatically populate the audit log table whenever a new mutation is applied to a different table.
This way we ensure that all changes (including those made by other applications) are meticulously recorded, enabling the enforcement
on the database-level and reducing the need for additional code in the applications.
This guide explains how to attach triggers to your Ent types (objects) and configure the schema migration to manage
both the triggers and the Ent schema as a single migration unit using Atlas.
:::info [Atlas Pro Feature](https://atlasgo.io/features#pro-plan)
Atlas support for [Triggers](https://atlasgo.io/atlas-schema/hcl#trigger) used in this guide is available exclusively
to Pro users. To use this feature, run:
```
atlas login
```
:::
## Install Atlas
<InstallationInstructions />
## Login to Atlas
```shell
$ atlas login a8m
//highlight-next-line-info
You are now connected to "a8m" on Atlas Cloud.
```
## Composite Schema
An `ent/schema` package is mostly used for defining Ent types (objects), their fields, edges and logic. Table triggers
or any other database native objects do not have representation in Ent models. A trigger function can be defined once,
and used in multiple triggers in different tables.
In order to extend our PostgreSQL schema to include both our Ent types and their triggers, we configure Atlas to
read the state of the schema from a [Composite Schema](https://atlasgo.io/atlas-schema/projects#data-source-composite_schema)
data source. Follow the steps below to configure this for your project:
1\. Let's define a simple schema with two types (tables): `users` and `user_audit_logs`:
```go title="ent/schema/user.go"
// User holds the schema definition for the User entity.
type User struct {
ent.Schema
}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("name"),
}
}
// UserAuditLog holds the schema definition for the UserAuditLog entity.
type UserAuditLog struct {
ent.Schema
}
// Fields of the UserAuditLog.
func (UserAuditLog) Fields() []ent.Field {
return []ent.Field{
field.String("operation_type"),
field.String("operation_time"),
field.String("old_value").
Optional(),
field.String("new_value").
Optional(),
}
}
```
Now, suppose we want to log every change to the `users` table and save it in the `user_audit_logs` table.
To achieve this, we need to create a trigger function on `INSERT`, `UPDATE` and `DELETE` operations and attach it to
the `users` table.
2\. Next step, we define a trigger function ( `audit_users_changes`) and attach it to the `users` table using the `CREATE TRIGGER` commands:
```sql title="schema.sql" {23,26,29}
-- Function to audit changes in the users table.
CREATE OR REPLACE FUNCTION audit_users_changes()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'INSERT') THEN
INSERT INTO user_audit_logs(operation_type, operation_time, new_value)
VALUES (TG_OP, CURRENT_TIMESTAMP, row_to_json(NEW));
RETURN NEW;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO user_audit_logs(operation_type, operation_time, old_value, new_value)
VALUES (TG_OP, CURRENT_TIMESTAMP, row_to_json(OLD), row_to_json(NEW));
RETURN NEW;
ELSIF (TG_OP = 'DELETE') THEN
INSERT INTO user_audit_logs(operation_type, operation_time, old_value)
VALUES (TG_OP, CURRENT_TIMESTAMP, row_to_json(OLD));
RETURN OLD;
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
-- Trigger for INSERT operations.
CREATE TRIGGER users_insert_audit AFTER INSERT ON users FOR EACH ROW EXECUTE FUNCTION audit_users_changes();
-- Trigger for UPDATE operations.
CREATE TRIGGER users_update_audit AFTER UPDATE ON users FOR EACH ROW EXECUTE FUNCTION audit_users_changes();
-- Trigger for DELETE operations.
CREATE TRIGGER users_delete_audit AFTER DELETE ON users FOR EACH ROW EXECUTE FUNCTION audit_users_changes();
```
3\. Lastly, we create a simple `atlas.hcl` config file with a `composite_schema` that includes both our Ent schema and
the custom triggers defined in `schema.sql`:
```hcl title="atlas.hcl"
data "composite_schema" "app" {
# Load the ent schema first with all tables.
schema "public" {
url = "ent://ent/schema"
}
# Then, load the triggers schema.
schema "public" {
url = "file://schema.sql"
}
}
env "local" {
src = data.composite_schema.app.url
dev = "docker://postgres/15/dev?search_path=public"
}
```
## Usage
After setting up our composite schema, we can get its representation using the `atlas schema inspect` command, generate
schema migrations for it, apply them to a database, and more. Below are a few commands to get you started with Atlas:
#### Inspect the Schema
The `atlas schema inspect` command is commonly used to inspect databases. However, we can also use it to inspect our
`composite_schema` and print the SQL representation of it:
```shell
atlas schema inspect \
--env local \
--url env://src \
--format '{{ sql . }}'
```
The command above prints the following SQL. Note, the `audit_users_changes` function and the triggers are defined after
the `users` and `user_audit_logs` tables:
```sql
-- Create "user_audit_logs" table
CREATE TABLE "user_audit_logs" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "operation_type" character varying NOT NULL, "operation_time" character varying NOT NULL, "old_value" character varying NULL, "new_value" character varying NULL, PRIMARY KEY ("id"));
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" character varying NOT NULL, PRIMARY KEY ("id"));
-- Create "audit_users_changes" function
CREATE FUNCTION "audit_users_changes" () RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
IF (TG_OP = 'INSERT') THEN
INSERT INTO user_audit_logs(operation_type, operation_time, new_value)
VALUES (TG_OP, CURRENT_TIMESTAMP, row_to_json(NEW));
RETURN NEW;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO user_audit_logs(operation_type, operation_time, old_value, new_value)
VALUES (TG_OP, CURRENT_TIMESTAMP, row_to_json(OLD), row_to_json(NEW));
RETURN NEW;
ELSIF (TG_OP = 'DELETE') THEN
INSERT INTO user_audit_logs(operation_type, operation_time, old_value)
VALUES (TG_OP, CURRENT_TIMESTAMP, row_to_json(OLD));
RETURN OLD;
END IF;
RETURN NULL;
END;
$$;
-- Create trigger "users_delete_audit"
CREATE TRIGGER "users_delete_audit" AFTER DELETE ON "users" FOR EACH ROW EXECUTE FUNCTION "audit_users_changes"();
-- Create trigger "users_insert_audit"
CREATE TRIGGER "users_insert_audit" AFTER INSERT ON "users" FOR EACH ROW EXECUTE FUNCTION "audit_users_changes"();
-- Create trigger "users_update_audit"
CREATE TRIGGER "users_update_audit" AFTER UPDATE ON "users" FOR EACH ROW EXECUTE FUNCTION "audit_users_changes"();
```
#### Generate Migrations For the Schema
To generate a migration for the schema, run the following command:
```shell
atlas migrate diff \
--env local
```
Note that a new migration file is created with the following content:
```sql title="migrations/20240712090543.sql"
-- Create "user_audit_logs" table
CREATE TABLE "user_audit_logs" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "operation_type" character varying NOT NULL, "operation_time" character varying NOT NULL, "old_value" character varying NULL, "new_value" character varying NULL, PRIMARY KEY ("id"));
-- Create "users" table
CREATE TABLE "users" ("id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY, "name" character varying NOT NULL, PRIMARY KEY ("id"));
-- Create "audit_users_changes" function
CREATE FUNCTION "audit_users_changes" () RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
IF (TG_OP = 'INSERT') THEN
INSERT INTO user_audit_logs(operation_type, operation_time, new_value)
VALUES (TG_OP, CURRENT_TIMESTAMP, row_to_json(NEW));
RETURN NEW;
ELSIF (TG_OP = 'UPDATE') THEN
INSERT INTO user_audit_logs(operation_type, operation_time, old_value, new_value)
VALUES (TG_OP, CURRENT_TIMESTAMP, row_to_json(OLD), row_to_json(NEW));
RETURN NEW;
ELSIF (TG_OP = 'DELETE') THEN
INSERT INTO user_audit_logs(operation_type, operation_time, old_value)
VALUES (TG_OP, CURRENT_TIMESTAMP, row_to_json(OLD));
RETURN OLD;
END IF;
RETURN NULL;
END;
$$;
-- Create trigger "users_delete_audit"
CREATE TRIGGER "users_delete_audit" AFTER DELETE ON "users" FOR EACH ROW EXECUTE FUNCTION "audit_users_changes"();
-- Create trigger "users_insert_audit"
CREATE TRIGGER "users_insert_audit" AFTER INSERT ON "users" FOR EACH ROW EXECUTE FUNCTION "audit_users_changes"();
-- Create trigger "users_update_audit"
CREATE TRIGGER "users_update_audit" AFTER UPDATE ON "users" FOR EACH ROW EXECUTE FUNCTION "audit_users_changes"();
```
#### Apply the Migrations
To apply the migration generated above to a database, run the following command:
```
atlas migrate apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
```
:::info Apply the Schema Directly on the Database
Sometimes, there is a need to apply the schema directly to the database without generating a migration file. For example,
when experimenting with schema changes, spinning up a database for testing, etc. In such cases, you can use the command
below to apply the schema directly to the database:
```shell
atlas schema apply \
--env local \
--url "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable"
```
Or, using the [Atlas Go SDK](https://github.com/ariga/atlas-go-sdk):
```go
ac, err := atlasexec.NewClient(".", "atlas")
if err != nil {
log.Fatalf("failed to initialize client: %w", err)
}
// Automatically update the database with the desired schema.
// Another option, is to use 'migrate apply' or 'schema apply' manually.
if _, err := ac.SchemaApply(ctx, &atlasexec.SchemaApplyParams{
Env: "local",
URL: "postgres://postgres:pass@localhost:5432/database?search_path=public&sslmode=disable",
AutoApprove: true,
}); err != nil {
log.Fatalf("failed to apply schema changes: %w", err)
}
```
:::
The code for this guide can be found in [GitHub](https://github.com/ent/ent/tree/master/examples/triggers).