Active Record with CQL
An overview of CQL's Active Record capabilities for defining models, interacting with your database, managing data integrity, and more.
This guide provides a comprehensive overview of Crystal Query Language (CQL)'s Active Record implementation. Active Record is a design pattern that connects database tables to classes (or structs in Crystal), allowing you to interact with your data through objects and methods rather than raw SQL queries.
CQL's Active Record module offers a powerful and intuitive way to manage your database records, inspired by established ORMs while leveraging Crystal's type safety and performance.
Core Concepts & Guides
This central README provides a high-level introduction. For in-depth information on specific aspects of CQL Active Record, please refer to the following guides:
Setup and Prerequisites: Initial configuration for using CQL and Active Record. (Covered below)
Defining Models: Learn how to define your Active Record models, map them to database tables, specify primary keys, and work with attributes.
CRUD Operations: Detailed guide on creating, reading, updating, and deleting records using Active Record methods.
Querying: Explore the powerful query interface, including direct finders, chainable queries, aggregations, and scopes.
Transactions: Ensure data integrity by using database transactions for multi-step operations.
Persistence Details: Understand how to check if a record is persisted and how to reload its data from the database.
Validations: Ensure data integrity by defining and using model validations.
Callbacks: Hook into the lifecycle of your models to trigger logic at specific events (e.g., before save, after create).
Relations: Define and use associations between models:
many_to_many
(covershas_and_belongs_to_many
)
Database Migrations: Manage your database schema changes over time.
Scopes: Define reusable query constraints for cleaner and more readable code.
Pagination: Easily paginate query results.
Prerequisites and Setup
Before getting started, ensure you have the following:
Crystal language installed (latest stable version recommended).
A supported relational database (e.g., PostgreSQL, MySQL) set up and accessible.
CQL added to your Crystal project.
Adding CQL to Your Project
Include CQL in your project's shard.yml
:
dependencies:
cql:
github: azutoolkit/cql # Or the appropriate source for your CQL version
version: "~> x.y.z" # Specify the version you are using
Then, run shards install
to download and install the dependency.
Database Connection Setup
You need to configure CQL to connect to your database. This is typically done by setting a database URL and opening a connection. You might also define a database context for your application.
require "cql"
# Example: Define your database connection URL (replace with your actual credentials)
# For PostgreSQL:
ENV_DB_URL = ENV["DATABASE_URL"]? || "postgres://username:password@localhost:5432/myapp_development"
# Define a database context. This is often a class or module that your models will reference.
# The name `AcmeDB` is used as a placeholder in these guides.
module AcmeDB
# Establishes and memoizes the database connection.
def self.db
@@db ||= DB.open(ENV_DB_URL)
end
# Optional: A method to close the connection if needed during shutdown or testing.
def self.close_db
@@db.try(&.close)
@@db = nil
end
end
# Ensure your models can reference this context, e.g.:
struct User
include CQL::ActiveRecord::Model(Int64)
db_context AcmeDB, :users
# ...
end
Note: The exact mechanism for defining your database context (AcmeDB
in the example) and making it accessible to your models should align with CQL's specific API and your application structure. Refer to CQL's core documentation for advanced database connection management, pooling, and context configuration.
Quick Overview of Key Features
Defining Models
Models are Crystal structs
including CQL::ActiveRecord::Model(PkType)
and use db_context
to link to a table.
See the full Defining Models Guide for details on attributes, primary keys, and more.
CRUD Operations
CQL provides intuitive methods for creating, reading, updating, and deleting records (e.g., save
, create!
, find?
, find_by!
, update!
, delete!
).
Explore the CRUD Operations Guide for comprehensive examples.
Querying
Fetch records using direct finders or build complex queries with a chainable interface (.where
, .order
, .limit
, etc.).
Dive into the Querying Guide for all query-building capabilities.
Transactions
Maintain data integrity with ACID-compliant database transactions. CQL provides both model-level transaction support and a service objects pattern for complex operations.
# Basic transaction usage
BankAccount.transaction do |tx|
account = BankAccount.find(1)
account.balance -= 100
account.save!
Transaction.create!(
amount: 100,
transaction_type: "withdrawal",
from_account_id: account.id,
created_at: Time.utc
)
# All operations succeed or fail together
end
Learn more in the Transactions Guide for maintaining data integrity across multiple operations.
Validations
Ensure data integrity with built-in or custom validation rules triggered before saving records.
Learn more in the Validations Guide.
Callbacks
Execute custom logic at different points in a model's lifecycle (e.g., before_save
, after_create
).
Consult the Callbacks Guide for usage details.
Relations
Define associations like belongs_to
, has_many
, has_one
, and many_to_many
to manage relationships between models.
Migrations
Manage database schema changes systematically using Crystal-based migration files.
See the Database Migrations Guide for how to write and run migrations.
Scopes
Create reusable query shortcuts to keep your code clean and expressive.
Read the Scopes Guide for defining and using scopes.
Last updated
Was this helpful?