Database Migrations
Database migrations are a crucial part of managing your application's database schema in a structured and version-controlled way. CQL provides a migration system that allows you to evolve your database schema over time as your application's requirements change.
Migrations are Crystal classes that define how to apply changes (up
method) and how to revert them (down
method).
What are Migrations?
As your application evolves, you'll often need to:
Create new tables.
Add, remove, or modify columns in existing tables.
Add or remove indexes.
Perform other schema alterations.
Migrations allow you to script these changes in Crystal code. Each migration file typically represents a single, atomic change to the database schema and is often timestamped or versioned to ensure changes are applied in the correct order.
Benefits of using migrations:
Version Control: Schema changes are tracked in your project's version control system (e.g., Git) alongside your application code.
Collaboration: Makes it easier for teams to manage database schema changes consistently across different development environments.
Reproducibility: Ensures that the database schema can be recreated reliably in any environment (development, testing, production).
Automation: Schema changes can be applied automatically as part of deployment processes.
Defining a Migration
Migrations in CQL are Crystal classes that inherit from CQL::Migration
(or a similar base class provided by the CQL framework).
File Naming and Location: Migration files are typically placed in a
db/migrate/
directory within your project. The filename often includes a timestamp or a sequential version number to denote the order of execution, followed by a descriptive name for the migration (e.g.,db/migrate/20231027000000_create_users.cr
).Migration Class Structure:
Key Points:
class CreateUsers < CQL::Migration
: Your migration class inherits fromCQL::Migration
.up(schema : CQL::Schema::Definition)
: This method is called when applying the migration. Theschema
object provides methods to manipulate the database structure.down(schema : CQL::Schema::Definition)
: This method is called when reverting (rolling back) the migration. It should undo the changes made by theup
method.Schema Definition API: The methods available on the
schema
object (e.g.,create_table
,add_column
,drop_table
,add_index
) and the column definition block (e.g.,t.text
,t.bool
,t.primary_key
,t.timestamps
) are specific to CQL. The exact syntax and available types (:text
,:integer
,:bool
,:datetime
, etc.) should be referenced from the CQL documentation you are using. The example above uses common conventions.
Common Migration Operations
Here are some common operations you might perform within the up
and down
methods of a migration:
Table Operations
Create Table (
schema.create_table :table_name do |t| ... end
):Drop Table (
schema.drop_table :table_name
): Used in thedown
method to remove a table created in theup
method.Alter Table (
schema.alter_table :table_name do |t| ... end
): Used for adding, removing, or changing columns on an existing table.
Column Operations (within create_table
or alter_table
)
create_table
or alter_table
)Add Column (
t.add_column :column_name, :type, options...
orschema.add_column :table, :column, :type, ...
):Remove Column (
t.remove_column :column_name
orschema.remove_column :table, :column
): Used to drop a column.Rename Column (
schema.rename_column :table, :old_name, :new_name
): Changes the name of an existing column.Change Column (
schema.change_column :table, :column, :new_type, options...
): Modifies the type or other options (likenull
,default
) of an existing column.
Index Operations
Add Index (
schema.add_index :table_name, :column_name_or_columns, options...
): Indexes improve query performance on frequently searched columns.Remove Index (
schema.remove_index :table_name, :column_name_or_columns
orname: :index_name
):
Foreign Keys
Foreign keys can often be defined when creating columns (e.g.,
t.references :author, foreign_key: true
) or added separately using methods likeschema.add_foreign_key
.
Important: The exact method names and options for schema manipulation (create_table
, add_column
, available data types like :text
, :integer
, :bool
, options like null:
, default:
, unique:
) can vary significantly between different database adapters (PostgreSQL, MySQL) and ORM/query builder implementations. Always refer to the specific CQL documentation for the version you are using to ensure you are using the correct API for schema definition.
Running Migrations
CQL will typically provide command-line tools or Rake tasks (if integrated with Rake) to manage and run your migrations.
Common migration commands (exact syntax will depend on CQL's tooling):
db:migrate
: Applies all pending migrations (those that haven't been run yet).db:rollback
: Reverts the last applied migration.db:schema:load
: Loads the schema from a schema file (e.g.,db/schema.cr
ordb/structure.sql
) into the database. This is often used to set up a new database quickly by loading the current schema state, bypassing running all migrations individually.db:schema:dump
: Creates or updates a schema file based on the current state of the database. This file represents the authoritative structure of your database.db:reset
: Typically drops the database, recreates it, and then loads the schema (or runs all migrations). Useful for resetting the database to a clean state in development.Checking Migration Status: Tools to see which migrations have been applied and which are pending.
Database Context: When running migrations, you often need to specify the database context (e.g., CONTEXT=AcmeDB
) if your application uses multiple databases or if the migration runner needs to know which configuration to use.
Schema File (db/schema.cr
or db/structure.sql
)
db/schema.cr
or db/structure.sql
)After migrations are run, CQL (like many ORMs) may maintain a db/schema.cr
or db/structure.sql
file.
db/schema.cr
(if applicable): This would be a Crystal representation of your current database schema, generated by inspecting the database. It's often used bydb:schema:load
.db/structure.sql
: Alternatively, a raw SQL dump of the database structure. This is database-agnostic for loading but less so for inspection.
This file serves as the canonical representation of your database schema at a given point in time. It's recommended to commit this file to version control.
Migrations are a powerful tool for database schema management. Writing reversible migrations (up
and down
methods) is crucial, especially for rolling back changes if needed.
Always test your migrations thoroughly, especially those involving data transformation or potentially destructive operations.
Last updated
Was this helpful?