Skip to content

Commit 6c3c99d

Browse files
committed
Use llms.txt bundles
1 parent 9b9f512 commit 6c3c99d

8 files changed

Lines changed: 8121 additions & 106 deletions

llms-db-migrations.txt

Lines changed: 376 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,376 @@
1+
# Ebean ORM Bundle — DB Migrations (Flattened)
2+
3+
> Flattened bundle. Content from source markdown guides is inlined below.
4+
5+
---
6+
7+
## Source: `add-ebean-db-migration-generation.md`
8+
9+
# Guide: Add Ebean Database Migration Generation to an Existing Maven Project
10+
11+
## Purpose
12+
13+
This guide provides step-by-step instructions for adding Ebean DB migration generation
14+
to an existing Maven project that already uses Ebean ORM. Ebean generates migrations by
15+
performing a diff of the current entity model against the previously recorded model state,
16+
producing platform-specific DDL SQL scripts.
17+
18+
These instructions are designed for AI agents and developers to follow precisely.
19+
20+
---
21+
22+
## Prerequisites
23+
24+
- An existing Maven project with Ebean ORM configured (entity beans present)
25+
- `ebean-test` is already a test-scoped dependency (from POM setup guide)
26+
- The project targets PostgreSQL (adjust `Platform.POSTGRES` for other databases)
27+
28+
---
29+
30+
## Step 1 — Verify migration dependencies
31+
32+
### Generation tooling (`ebean-ddl-generator`)
33+
34+
`ebean-test` (already present as a test dependency) transitively includes
35+
`ebean-ddl-generator`, which provides the `DbMigration` class. No additional dependency
36+
is required for generation.
37+
38+
### Runtime migration runner (`ebean-migration`)
39+
40+
`ebean-migration` is the library that runs migrations on application startup.
41+
It is typically included **transitively** via `io.ebean:ebean-postgres` (or the
42+
equivalent platform dependency). Verify it is on the classpath by running:
43+
44+
```bash
45+
mvn dependency:tree | grep ebean-migration
46+
```
47+
48+
If it is **not** present transitively, add it explicitly as a compile-scope dependency:
49+
50+
```xml
51+
<dependency>
52+
<groupId>io.ebean</groupId>
53+
<artifactId>ebean-migration</artifactId>
54+
<version>${ebean.version}</version>
55+
</dependency>
56+
```
57+
58+
---
59+
60+
## Step 2 — Create `GenerateDbMigration.java`
61+
62+
Create the following class in `src/test/java/main/`. This `main` method is run manually
63+
by a developer (or AI agent) whenever entity beans change and a new migration is needed.
64+
65+
```java
66+
package main;
67+
68+
import io.ebean.annotation.Platform;
69+
import io.ebean.dbmigration.DbMigration;
70+
71+
import java.io.IOException;
72+
73+
/**
74+
* Generate the next database migration based on a diff of the entity model.
75+
* Run this main method after making entity bean changes to produce the migration SQL.
76+
*/
77+
public class GenerateDbMigration {
78+
79+
public static void main(String[] args) throws IOException {
80+
81+
DbMigration migration = DbMigration.create();
82+
migration.setPlatform(Platform.POSTGRES);
83+
84+
migration.setVersion("1.1"); // set to the next migration version
85+
migration.setName("add-customer"); // short description of the change
86+
87+
migration.generateMigration();
88+
}
89+
}
90+
```
91+
92+
### Version naming convention
93+
94+
Ebean supports two common version formats — choose one and apply it consistently:
95+
96+
| Format | Example | Notes |
97+
|--------|---------|-------|
98+
| **Date-based** | `20240820` | `YYYYMMDD`; used when changes are tied to dates; easily sortable |
99+
| **Semantic** | `1.1`, `1.2`, `2.0` | Traditional versioning; useful for release-based workflows |
100+
101+
The version controls execution order — Ebean runs migrations in ascending version order.
102+
103+
### Name convention
104+
105+
The `name` should be a short, lowercase, hyphenated description of the change:
106+
- `add-customer-email`
107+
- `rename-machine-type`
108+
- `drop-unused-columns`
109+
110+
---
111+
112+
## Step 3 — Configure the output path (if needed)
113+
114+
By default, migration files are written to `src/main/resources/dbmigration/` relative
115+
to the **current working directory** when `generateMigration()` is called. This is
116+
usually the module root, which is correct for single-module projects.
117+
118+
For **multi-module projects** where `GenerateDbMigration` is in a submodule but the
119+
resources directory is at a different relative path, specify it explicitly:
120+
121+
```java
122+
// Relative path from the working directory (project root) to the module's resources
123+
migration.setPathToResources("my-module/src/main/resources");
124+
```
125+
126+
---
127+
128+
## Step 4 — Run `GenerateDbMigration` to produce the first migration
129+
130+
Run the `main` method via the IDE or Maven:
131+
132+
```bash
133+
# Run via Maven exec plugin (or use IDE run configuration)
134+
mvn test-compile exec:java \
135+
-Dexec.mainClass="main.GenerateDbMigration" \
136+
-Dexec.classpathScope="test" \
137+
-pl <your-module>
138+
```
139+
140+
Ebean migration generation runs in **offline mode** — no database connection is required.
141+
142+
### Expected output files
143+
144+
After running, two files are created per migration in `src/main/resources/dbmigration/`:
145+
146+
```
147+
src/main/resources/dbmigration/
148+
1.1__add-customer.sql ← DDL SQL to apply (commit this)
149+
model/
150+
1.1__add-customer.model.xml ← logical model diff XML (commit this)
151+
```
152+
153+
Both files must be committed to source control. The `.model.xml` file records the
154+
logical state of the diff and is used by subsequent migration generations to determine
155+
what has changed.
156+
157+
If **no entity beans have changed** since the last migration, the command outputs:
158+
```
159+
DbMigration - no changes detected - no migration written
160+
```
161+
162+
---
163+
164+
## Step 5 — Enable the migration runner
165+
166+
Configure Ebean to run pending migrations automatically on application startup.
167+
168+
### Preferred approach — programmatic via `DatabaseBuilder`
169+
170+
Set `runMigration(true)` directly on the `DatabaseBuilder` when constructing
171+
the `Database` bean. This is the preferred approach as it is explicit, co-located with
172+
the database configuration, and does not rely on external property files.
173+
174+
In the `@Factory` class that builds the `Database` bean (see the database configuration
175+
guide), add `.runMigration(true)` to the builder chain:
176+
177+
```java
178+
@Bean
179+
Database database(ConfigWrapper config) {
180+
var dataSource = DataSourceBuilder.create()
181+
.url(config.getDatabaseUrl())
182+
.username(config.getDatabaseUser())
183+
.password(config.getDatabasePassword())
184+
// ... other datasource settings ...
185+
;
186+
187+
return Database.builder()
188+
.name("db")
189+
.dataSourceBuilder(dataSource)
190+
.runMigration(true) // run pending migrations on startup
191+
.build();
192+
}
193+
```
194+
195+
If migrations should only run in certain environments (e.g., not in production, or
196+
only when a config flag is set), make it conditional:
197+
198+
```java
199+
.runMigration(config.isRunMigrations()) // driven by config value
200+
```
201+
202+
### Alternative — via application properties
203+
204+
If programmatic configuration is not available or not preferred, set the property
205+
in `src/main/resources/application.properties`:
206+
207+
```properties
208+
ebean.migration.run=true
209+
```
210+
211+
Or in `src/main/resources/application.yaml`:
212+
```yaml
213+
ebean:
214+
migration:
215+
run: true
216+
```
217+
218+
For a **named database** (i.e., `Database.builder().name("mydb")`), use the database
219+
name in the property key:
220+
221+
```properties
222+
ebean.mydb.migration.run=true
223+
```
224+
225+
### What the runner does at startup
226+
227+
When migration running is enabled, Ebean will on each application start:
228+
1. Look at the migrations in `src/main/resources/dbmigration/`
229+
2. Compare against the `db_migration` table (created automatically on first run)
230+
3. Apply any migrations that have not yet been executed, in version order
231+
4. Record each successfully applied migration in `db_migration`
232+
233+
---
234+
235+
## Step 6 — Commit the migration files
236+
237+
Add both generated files to source control:
238+
239+
```bash
240+
git add src/main/resources/dbmigration/1.1__add-customer.sql
241+
git add src/main/resources/dbmigration/model/1.1__add-customer.model.xml
242+
git commit -m "Add db migration 1.1: add-customer"
243+
```
244+
245+
---
246+
247+
## Ongoing workflow — generating subsequent migrations
248+
249+
For each future set of entity bean changes:
250+
251+
1. Make changes to the entity bean classes
252+
2. Update `GenerateDbMigration.java` with the **new version** and **new name**:
253+
```java
254+
migration.setVersion("1.2");
255+
migration.setName("add-address-table");
256+
```
257+
3. Run the `main` method — a new `.sql` and `.model.xml` pair is written
258+
4. Review the generated `.sql` to confirm it reflects the intended changes
259+
5. Commit both files
260+
261+
---
262+
263+
## Understanding the output files
264+
265+
### Apply SQL (`.sql`)
266+
267+
The apply SQL file contains the DDL that will be executed against the database:
268+
269+
```sql
270+
-- apply changes
271+
alter table customer add column email varchar(255);
272+
```
273+
274+
### Model XML (`.model.xml`)
275+
276+
The model XML records the logical diff in a database-agnostic format. Ebean uses
277+
this file on the next generation run to determine what has already been captured.
278+
It is not executed against the database.
279+
280+
```xml
281+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
282+
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration">
283+
<changeSet type="apply">
284+
<addColumn tableName="customer">
285+
<column name="email" type="varchar(255)"/>
286+
</addColumn>
287+
</changeSet>
288+
</migration>
289+
```
290+
291+
---
292+
293+
## Optional configurations
294+
295+
### Multiple database platforms
296+
297+
To generate migrations for multiple platforms simultaneously, use `addPlatform()`
298+
instead of `setPlatform()`:
299+
300+
```java
301+
migration.addPlatform(Platform.POSTGRES);
302+
migration.addPlatform(Platform.SQLSERVER17);
303+
migration.addPlatform(Platform.MYSQL);
304+
```
305+
306+
Each platform gets its own subdirectory under `dbmigration/`.
307+
308+
### Include index
309+
310+
When enabled the migration generation also generates a file that contains
311+
all the migrations and their associated hashes. This is a performance
312+
optimisation (that will become the default) and means that the migration
313+
runner just needs to read the one resource and has the pre-computed hash
314+
values (so does not need to read each migration resource and compute the
315+
hash for each of those at runtime).
316+
317+
```java
318+
migration.setIncludeIndex(true);
319+
```
320+
321+
### Strict mode
322+
323+
Strict mode (on by default) errors if there are any pending drops not yet applied.
324+
Set to `false` to allow generation to proceed regardless:
325+
326+
```java
327+
migration.setStrictMode(false);
328+
```
329+
330+
### Applying pending drops
331+
332+
Destructive changes (drop column, drop table) are **not** included in the apply
333+
SQL by default — they are recorded as `pendingDrops` in the model XML. This allows
334+
the application to be deployed without immediately dropping columns (important for
335+
rolling deployments).
336+
337+
The migration runner logs a message when pending drops exist:
338+
```
339+
INFO DbMigration - Pending un-applied drops in versions [1.1]
340+
```
341+
342+
When ready to apply the drops, set `setGeneratePendingDrop` to the version that
343+
contains the pending drops:
344+
345+
```java
346+
migration.setVersion("1.3");
347+
migration.setName("drop-pending-from-1.1");
348+
migration.setGeneratePendingDrop("1.1"); // apply drops recorded in version 1.1
349+
migration.generateMigration();
350+
```
351+
352+
### Custom dbSchema
353+
354+
If the project uses a named Postgres schema (set via `ebean.dbSchema` in
355+
`application.properties`), no additional configuration is needed in
356+
`GenerateDbMigration` — Ebean picks up the schema from the application config
357+
automatically when running in offline mode.
358+
359+
```properties
360+
# application.properties
361+
ebean.dbSchema=myschema
362+
```
363+
364+
---
365+
366+
## Troubleshooting
367+
368+
| Symptom | Likely cause | Fix |
369+
|---------|-------------|-----|
370+
| `no changes detected - no migration written` | Entity beans unchanged since last migration | Make entity bean changes first, then re-run |
371+
| `DbMigration - Pending un-applied drops` | A previous migration has drops not yet applied | Either suppress with `setStrictMode(false)` or apply drops with `setGeneratePendingDrop(...)` |
372+
| Generated SQL is empty or wrong | Wrong working directory path | Set `setPathToResources(...)` to the correct module-relative path |
373+
| `ClassNotFoundException` for entity classes | Test classpath not including main classes | Ensure `exec.classpathScope=test` or run via IDE with test classpath |
374+
| Migrations not running on startup | Property key wrong or `ebean-migration` missing | Verify `ebean[.name].migration.run=true` and that `ebean-migration` is on the classpath |
375+
376+

0 commit comments

Comments
 (0)