1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//! Migration traits — raw SQL (backward-compat) and async schema-builder.
// ── RawMigration ──────────────────────────────────────────────────────────────
/// A raw-SQL migration that returns SQL strings synchronously.
///
/// Used internally by [`EmbeddedMigration`], [`FileSource`], and the
/// `.raw_migration()` runner method. Framework crates that ship their own
/// tables embed their SQL via this trait.
///
/// [`EmbeddedMigration`]: crate::migrate::EmbeddedMigration
/// [`FileSource`]: crate::migrate::FileSource
// ── Migration (async schema-builder) ─────────────────────────────────────────
/// A schema-builder migration — async, receives a live [`SchemaExecutor`].
///
/// This is the preferred API for application migrations. Use the typed DSL
/// in `up` to describe what to create and `down` to reverse it.
///
/// # Example
///
/// ```rust,ignore
/// # use rok_fluent::migrate::{Migration, MigrationRunner, SchemaExecutor};
/// use async_trait::async_trait;
///
/// pub struct CreateUsersTable;
///
/// #[async_trait]
/// impl Migration for CreateUsersTable {
/// fn name(&self) -> &str { "2026_05_18_000001_create_users_table" }
///
/// async fn up(&self, schema: &SchemaExecutor) -> anyhow::Result<()> {
/// schema.create("users", |t: &mut rok_fluent::migrate::TableBuilder| {
/// t.id();
/// t.string("email").not_null().unique();
/// t.string("name").not_null();
/// t.timestamps();
/// }).await
/// }
///
/// async fn down(&self, schema: &SchemaExecutor) -> anyhow::Result<()> {
/// schema.drop_table_if_exists("users").await
/// }
/// }
/// ```
///
/// [`SchemaExecutor`]: crate::migrate::schema::SchemaExecutor