You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: documentation/topics/development/migrations-and-tasks.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,6 +25,10 @@ dev migrations and run them.
25
25
26
26
For more information on generating migrations, run `mix help ash_postgres.generate_migrations` (the underlying task that is called by `mix ash.migrate`)
27
27
28
+
When you remove a resource from your domain, run the migration generator (e.g. `mix ash_postgres.generate_migrations --name remove_my_resource`). It will generate a migration to drop the table and remove the snapshot for that table.
29
+
30
+
When you rename a resource's table (e.g. change the `table "..."` in the `postgres do` block), the generator will ask whether you are renaming the table. If you answer yes, it generates a single `rename table(...), to: table(...)` migration so the table is renamed in place and data and foreign keys are preserved.
31
+
28
32
> ### all_tenants/0 {: .info}
29
33
>
30
34
> If you are using schema-based multitenancy, you will also need to define a `all_tenants/0` function in your repo module. See `AshPostgres.Repo` for more.
When you're building an Ash application against a database you don't own or control — such as a shared company database, a legacy system, or a third-party service's database — you need a workflow that lets you iterate on your Ash resources without generating migrations. The `--fragments` and `--no-migrations` options to `mix ash_postgres.gen.resources` are designed for exactly this.
10
+
11
+
## The Problem
12
+
13
+
Normally, Ash resources are the source of truth for your database schema, and migrations are generated from them. But when the database is managed externally:
14
+
15
+
- You don't want Ash generating migrations for a schema you don't control
16
+
- The upstream schema may change, and you need to regenerate your resources to match
17
+
- You still want to customize your resources with actions, calculations, validations, and other Ash features — without losing those customizations on regeneration
18
+
19
+
## The Workflow
20
+
21
+
### 1. Generate resources with `--fragments` and `--no-migrations`
22
+
23
+
```bash
24
+
mix ash_postgres.gen.resources MyApp.ExternalDb \
25
+
--tables users,orders,products \
26
+
--no-migrations \
27
+
--fragments
28
+
```
29
+
30
+
This creates two files per table:
31
+
32
+
-**The resource file** (e.g., `lib/my_app/external_db/user.ex`) — contains `use Ash.Resource`, the `postgres` block, and any actions. This is *your* file to customize.
33
+
-**The fragment file** (e.g., `lib/my_app/external_db/user/model.ex`) — contains the attributes, relationships, and identities introspected from the database. This file is regenerated by the tool.
34
+
35
+
The resource file will include `migrate? false` in its `postgres` block (from `--no-migrations`), telling Ash not to generate migrations for it:
36
+
37
+
```elixir
38
+
defmoduleMyApp.ExternalDb.Userdo
39
+
useAsh.Resource,
40
+
domain:MyApp.ExternalDb,
41
+
data_layer:AshPostgres.DataLayer,
42
+
fragments: [MyApp.ExternalDb.User.Model]
43
+
44
+
postgres do
45
+
table "users"
46
+
repo MyApp.Repo
47
+
migrate? false
48
+
end
49
+
end
50
+
```
51
+
52
+
The fragment file contains the schema details:
53
+
54
+
```elixir
55
+
defmoduleMyApp.ExternalDb.User.Modeldo
56
+
useSpark.Dsl.Fragment,
57
+
of:Ash.Resource
58
+
59
+
attributes do
60
+
uuid_primary_key :id
61
+
attribute :email, :string, public?:true
62
+
attribute :name, :string, public?:true
63
+
# ...
64
+
end
65
+
66
+
relationships do
67
+
has_many :orders, MyApp.ExternalDb.Order
68
+
# ...
69
+
end
70
+
71
+
identities do
72
+
identity :unique_email, [:email]
73
+
end
74
+
end
75
+
```
76
+
77
+
### 2. Customize your resources
78
+
79
+
Add actions, calculations, validations, changes, and anything else to the **resource file**. This is your space:
### 3. Regenerate fragments when the schema changes
110
+
111
+
When the upstream database schema changes (new columns, new tables, changed relationships), re-run the same command:
112
+
113
+
```bash
114
+
mix ash_postgres.gen.resources MyApp.ExternalDb \
115
+
--tables users,orders,products \
116
+
--no-migrations \
117
+
--fragments
118
+
```
119
+
120
+
Because the resource files already exist, **only the fragment files are regenerated**. Your customizations in the resource files are untouched.
121
+
122
+
### 4. Review the diff
123
+
124
+
After regeneration, review the changes with `git diff` to see what changed in the schema. New columns will appear as new attributes, altered relationships will be updated, and so on.
125
+
126
+
## Key Points
127
+
128
+
-**`--fragments`** splits generated schema details into a separate `Model` fragment module, keeping your resource file safe from regeneration
129
+
-**`--no-migrations`** prevents migration generation and adds `migrate? false` to the `postgres` block
130
+
-**Fragment files are disposable** — they are regenerated from the database each time. Don't put custom code in them.
131
+
-**Resource files are yours** — once created on the first run, they won't be overwritten by subsequent runs
132
+
- You can also use `--skip-tables` to exclude tables, `--tables` to scope to specific schemas (e.g., `accounts.`), and `--extend` to apply extensions to generated resources
0 commit comments