This example demonstrates Haxe-authored, type-safe Ecto migrations via the @:migration annotation.
Status (Experimental): Migrations are executable by Ecto via an opt-in migration build (
build-migrations.hxml) that emits timestamped.exsfiles underpriv/repo/migrations/. The DSL is still evolving; treatalterTablesupport as experimental.
Prerequisites: 03-phoenix-app completed
Difficulty: 🟡 Intermediate
Time: 30 minutes
- Define database schemas using
@:migrationannotation - Create tables, columns, indexes, and foreign keys type-safely
- Integrate with Elixir's migration workflow
- Handle up/down migration patterns
- Migration DSL: Type-safe migration definitions in Haxe
- Foreign Keys: Automatic relationship creation and constraints
- Indexes: Single and composite index creation
- Constraints: Check constraints and validation rules
- Compile-time validation: Registry-backed checks during macro expansion (experimental)
cd examples/04-ecto-migrations
# Compile the migrations to runnable Ecto `.exs` files
haxe build-migrations.hxml
# Or via Mix:
# mix haxe.compile.migrations
# Inspect the generated migrations
ls priv/repo/migrations
# (Optional) Compile the intermediate `.ex` output (useful for debugging the DSL transform)
haxe build.hxml
# Inspect the intermediate output under lib/
ls lib/migrationsHaxe Source:
import ecto.Migration;
import ecto.Migration.ColumnType;
@:migration({timestamp: "20240101120000"})
class CreateUsers extends Migration {
public function up(): Void {
createTable("users")
.addId()
.addColumn("name", ColumnType.String(), {nullable: false})
.addColumn("email", ColumnType.String(), {nullable: false})
.addTimestamps()
.addIndex(["email"], {unique: true});
}
public function down(): Void {
dropTable("users");
}
}Generated Elixir (runnable Ecto migration):
After haxe build-migrations.hxml, see:
priv/repo/migrations/*_create_users.exs
Example generated shape:
defmodule ReflaxeExample.Repo.Migrations.CreateUsers do
use Ecto.Migration
def up do
create table(:users) do
add :name, :string, null: false
add :email, :string, null: false
timestamps()
end
create unique_index(:users, [:email])
end
def down do
drop table(:users)
end
endForeign Keys:
createTable("posts").addReference("user_id", "users");Composite Indexes:
createTable("posts").addIndex(["published", "inserted_at"]);Check Constraints:
createTable("posts").addCheckConstraint("positive_view_count", "view_count >= 0");# Generate new migration
mix haxe.gen.migration CreateUsers
# This creates:
# - src_haxe/migrations/CreateUsers.hx (Haxe source skeleton with a timestamp)
# Compile runnable `.exs` migrations (use the migration-only build file)
haxe build-migrations.hxml- Write migration in Haxe using
@:migration - Compile runnable migrations with
haxe build-migrations.hxml - Run
mix ecto.migratein a real project (Phoenix app) with a configured Repo - (Optional) Use
haxe build.hxmlto inspect intermediate.exoutput when debugging transforms
- Type Safety: Compile-time validation of migration structure
- Reusability: Share migration logic across projects
- Consistency: Standardized migration patterns
- Integration: Works with existing Ecto tooling