README

A high-performance, type-safe ORM for Crystal applications.

Build fast, reliable database applications with compile-time safety and exceptional performance.

Type Safety Database Support


What Makes CQL Special?

CQL brings compile-time safety and performance optimization to Crystal applications. Unlike traditional ORMs that check for errors at runtime, CQL validates your queries, relationships, and data access patterns before your code executes.

# Type-safe queries that catch errors at compile time
users = User.where(active: true)      # Type checked
           .order(created_at: :desc)  # Validates column exists
           .limit(10)                 # Validates parameter type
           .all

# This would fail at COMPILE TIME, not runtime:
# User.where(nonexistent: true)      # Compile error!
# User.where(age: "invalid")         # Type mismatch caught early!

Key Features & Benefits

Performance Optimized

  • Zero-allocation queries through Crystal's compile-time optimizations

  • Connection pooling built-in for high-concurrency applications

  • Query caching with multiple cache backends (Memory, Redis)

  • N+1 query detection and performance monitoring tools

Type Safety at Compile Time

  • Catch bugs early - invalid queries fail at compile time

  • Full IDE support with autocompletion and refactoring

  • Relationship safety - no more runtime association errors

  • Query validation - SQL structure validated before deployment

Developer Experience

  • ActiveRecord-style API - familiar patterns for Rails developers

  • Automatic schema management - migrations with rollback support

  • Rich query DSL - expressive and readable database queries

  • Built-in validations - data integrity without boilerplate

Production Ready

  • PostgreSQL, MySQL, SQLite support through Crystal DB drivers

  • Transaction management with rollback safety

  • Performance monitoring and query analysis tools

  • Multiple design patterns - Active Record, Repository, Data Mapper support


Quick Start

Get up and running in under 5 minutes:

Try CQL Interactively

Explore CQL features with our interactive examples runner:

# Clone the repository
git clone https://github.com/azutoolkit/cql
cd cql

# Run the interactive examples
crystal examples/run_examples.cr

Choose from organized categories:

  • Basic Examples - Simple caching and core concepts

  • Advanced Caching - Enterprise-grade caching patterns

  • Configuration - Environment setup and best practices

  • Migrations - Database schema evolution

  • Performance - Monitoring and optimization

  • Framework Integration - Web framework examples

  • Complete Blog App - Full-featured application demo

1. Add to Your Project

# shard.yml
dependencies:
  cql:
    github: azutoolkit/cql
    version: ~> 0.0.435
  pg: # PostgreSQL driver
    github: will/crystal-pg
    version: ~> 0.26.0

2. Define Your Schema

# Set up your database schema
BlogDB = CQL::Schema.define(
  :blog_schema,
  adapter: CQL::Adapter::Postgres,
  uri: ENV["DATABASE_URL"]
) do
  table :users do
    primary :id, Int64
    text :name
    text :email
    boolean :active, default: "1"
    timestamps
  end

  table :posts do
    primary :id, Int64
    text :title
    text :content
    bigint :user_id
    boolean :published, default: "0"
    timestamps
    foreign_key [:user_id], references: :users, references_columns: [:id]
  end
end

3. Create Your First Model

struct User
  include CQL::ActiveRecord::Model(Int64)
  db_context BlogDB, :users

  getter id : Int64?
  getter name : String
  getter email : String
  getter active : Bool = true
  getter created_at : Time?
  getter updated_at : Time?

  # Type-safe relationships
  has_many :posts, foreign_key: :user_id

  # Built-in validations
  validate :name, presence: true, size: 2..50
  validate :email, presence: true, match: /@/

  def initialize(@name : String, @email : String, @active : Bool = true)
  end
end

4. Start Building

# Create records with validation
user = User.create!(name: "Alice", email: "alice@example.com")

# Type-safe queries
active_users = User.where(active: true)
                  .order(created_at: :desc)
                  .limit(50)
                  .all

# Work with relationships
user = User.find!(1)
posts = user.posts.all

puts "User #{user.name} has #{posts.size} posts"

Database Support

Supported databases with their Crystal DB drivers:

Database
Driver
Connection String Example

PostgreSQL

pg

postgres://user:pass@localhost/mydb

MySQL

mysql

mysql://user:pass@localhost/mydb

SQLite

sqlite3

sqlite3://./database.db


Advanced Features

Relationships Made Simple

# Define relationships with type safety
struct Post
  include CQL::ActiveRecord::Model(Int64)
  db_context BlogDB, :posts

  getter id : Int64?
  getter title : String
  getter content : String
  getter user_id : Int64
  getter published : Bool = false

  belongs_to :user, User, foreign_key: :user_id
  has_many :comments, Comment, foreign_key: :post_id

  def initialize(@title : String, @content : String, @user_id : Int64)
  end
end

# Work with relationships efficiently
post = Post.find!(1)
author = post.user                    # Type: User
comments = post.comments.all          # Type: Array(Comment)

Powerful Query DSL

# Complex queries with full type safety
recent_posts = Post.where(published: true)
                  .where { users.created_at >= 1.month.ago }
                  .order(created_at: :desc)
                  .limit(100)
                  .all

# Use the CQL Query builder for complex joins
posts_with_authors = BlogDB.query
  .from(:posts)
  .join(:users) { |j| j.posts.user_id.eq(j.users.id) }
  .where{ posts.published: true }
  .select(posts: [:title, :content], users: [:name])
  .all({title: String, content: String, name: String})

Automatic Schema Management

# Migrations with full rollback support
class CreateUsers < CQL::Migration(1)
  def up
    schema.create :users do
      primary :id, Int64, auto_increment: true
      text :name, null: false
      text :email, null: false
      boolean :active, default: true
      timestamps
    end

    schema.alter :users do
      create_index :idx_users_email, [:email], unique: true
    end

    schema.users.create!
  end

  def down
    schema.users.drop!
  end
end

Built-in Validations

struct User
  include CQL::ActiveRecord::Model(Int64)
  db_context BlogDB, :users

  # ... properties ...

  # Comprehensive validation support
  validate :name, presence: true, size: 2..50
  validate :email, required: true, match: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validate :age, gt: 0, lt: 120
  validate :password_confirmation, confirmation: :password
  validate :terms, accept: true

  def initialize(@name : String, @email : String)
  end
end

# Validate before saving
user = User.new(name: "Alice", email: "alice@example.com")
if user.valid?
  user.save!
else
  puts user.errors.messages
end

Why Choose CQL?

For High-Performance Applications

  • APIs serving high request volumes

  • Real-time applications requiring low latency

  • Data-intensive processing applications

  • Microservices architecture

For Enterprise Development

  • Large team collaboration with type safety

  • Long-term maintenance requirements

  • Complex business logic with data integrity

  • Compliance and audit requirements

For Modern Development

  • Type-safe development practices

  • DevOps and CI/CD pipeline integration

  • Container-based deployment strategies

  • Cloud-native architecture patterns


Complete Documentation

Getting Started

Core Features

Quick Reference

I want to...

Go to...

Set up a new project

Define models and relationships

Build complex queries

Handle database changes

Deploy to production


Ready to Get Started?

# Try the interactive examples first
crystal examples/run_examples.cr

# Or install CQL and start building
shards install

Try Interactive Examples →Start with Installation →


Built with Crystal's performance and safety in mind.

All examples are tested with the latest CQL version.

DocumentationExamplesFAQIssues

Last updated

Was this helpful?