class CQL::ActiveRecord::Relations::Collection(Target, Pk)

Overview

Collection for one-to-many relationships.

This class manages the relationship between two tables through a foreign key column in the target table and provides methods to manage the association between the two tables and query records in the associated table based on the foreign key value of the parent record.

has_many returns one, for example has_many :posts, Post, foreign_key: :user_id in User:

user.posts.create(title: "Hello World")
user.posts.size # => 1

Included Modules

Direct Known Subclasses

Defined in:

active_record/relations/collection.cr

Constructors

Instance Method Summary

Macros inherited from module CQL::ActiveRecord::Relations::BaseRelation

build_query(model_class) build_query, destroy_dependent(record, association) destroy_dependent, ensure_saved(record) ensure_saved, safe_db_operation(&block) safe_db_operation, safe_foreign_key(record, key, pk_type) safe_foreign_key, safe_id(record, pk_type) safe_id, underscore_name(class_name) underscore_name

Constructor Detail

def self.new(key : Symbol, id : Pk, cascade : Bool = false, query base_query : CQL::Query | Nil = nil, auto_load : Bool = false, dependent : Symbol = :nullify) #

Initialize the collection class for a one-to-many relationship

  • param : key (Symbol) - The foreign key in the target table (e.g., :user_id)
  • param : id (Pk) - The id value for the parent record
  • param : cascade (Bool) - Whether to delete associated records when parent is deleted (deprecated, use dependent)
  • param : query (CQL::Query) - Base query; the collection scopes it to the parent and operations run on clones of it
  • param : auto_load (Bool) - Whether to automatically load associated records
  • param : dependent (Symbol) - Dependency handling strategy
  • return : Collection(Target, Pk)

Example

CQL::ActiveRecord::Relations::Collection(Post, Int64).new(
  :user_id,
  1_i64,
  query: CQL::Query.new(Post.schema).from(Post.table),
  dependent: :destroy
)

[View source]

Instance Method Detail

def <<(record : Target) #

Adds a record to the collection, as #create(record) does.

  • param : record (Target)
  • return : Array(Target)
  • raise : CQL::RecordInvalid when a saved record fails its validations

Example

user.posts << Post.new(title: "Hello World")

[View source]
def [](index : Int32) #

Get element at index, raises if out of bounds

  • param : index (Int32)
  • return : Target

[View source]
def []?(index : Int32) #

Get element at index, returns nil if out of bounds

  • param : index (Int32)
  • return : Target?

[View source]
def _inject_preloaded(records : Array(Target)) : Nil #

Inject preloaded records without database query Used by eager loading/preload to set association data that was loaded in a batch query to avoid N+1 queries.

  • param : records (Array(Target)) - The preloaded records
  • return : Nil

[View source]
def all(type : T.class) : Array(T) forall T #

Execute a query and return results of specified type This is used for method chaining with where, limit, offset, etc.

  • param : type (Class) - The model type to return
  • return : Array(T)

Example

user.posts.offset(2).all(Post)

[View source]
def all : Array(Target) #

Returns all associated records

  • return : Array(Target)

Example

user.posts.all

[View source]
def all?(&block : Target -> Bool) #

Check if all records match the given block

  • param : block (Block(Target, Bool))
  • return : Bool

[View source]
def any?(&block : Target -> Bool) #

Check if any record matches the given block

  • param : block (Block(Target, Bool))
  • return : Bool

[View source]
def build(**attributes) #

Creates a new, unsaved record with the parent association set

  • param : attributes (NamedTuple | Hash(Symbol, DB::Any))
  • return : Target

Example

post = user.posts.build(title: "New Post")
post.save! # => true

[View source]
def clear #

Clears all associated records from the parent record with the association's dependent: strategy (:destroy, :delete_all, or :nullify, the default, which needs a nullable foreign key)

  • return : Int64 - Number of records affected

Example

user.posts.create(title: "Hello World")
user.posts.clear

[View source]
def concat(records : Array(Target)) : Array(Target) #

Add multiple records to the collection

  • param : records (Array(Target))
  • return : Array(Target)

[View source]
def count : Int64 #

Count records directly from database without loading

  • return : Int64

[View source]
def create(record : Target) #

Associates record with the parent: a new record is inserted without validations, a saved one (soft-deleted included) gets its foreign key updated with save!.

  • param : record (Target)
  • return : Target
  • raise : RelationError, or CQL::RecordInvalid when a saved record fails its validations

[View source]
def create(**attributes) #

Creates a new record with the given attributes and saves it

  • param : attributes (NamedTuple | Hash(Symbol, DB::Any))
  • return : Target
  • raise : RelationError

Example

user.posts.create(title: "Hello World")

[View source]
def delete(record : Target) #

Delete the associated record from the parent record if it exists

  • param : record (Target)
  • return : Bool

Example

post = user.posts.create(title: "Hello World")
user.posts.delete(post) # => true

[View source]
def delete(id : Pk) #

Delete the associated record from the parent record if it exists

  • param : id (Pk)
  • return : Bool

Example

post = user.posts.create(title: "Hello World")
user.posts.delete(post.id!) # => true

[View source]
def delete_all : Int64 #

Delete all associated records

  • return : Int64 - Number of records deleted

[View source]
def each(&block : Target -> ) #

Implements the each method for the Enumerable module

  • param : block (Block(Target))
  • return : Nil

[View source]
def each_with_index(&block : Target, Int32 -> ) #

Each with index

  • param : block (Block(Target, Int32))
  • return : Nil

[View source]
def empty? #

Checks if the collection is empty

  • return : Bool

Example

user.posts.empty?

[View source]
def exists?(**attributes) #

Checks if any records exist with the given attributes

  • param : attributes (NamedTuple)
  • return : Bool

[View source]
def find(**attributes) #

Find associated records matching the given attributes

  • param : attributes (NamedTuple | Hash(Symbol, DB::Any))
  • return : Array(Target)

Example

user.posts.find(title: "Hello World")

[View source]
def find(&block : Target -> Bool) #

Find the first record matching the given block

  • param : block (Block(Target, Bool))
  • return : Target?

[View source]
def find_by(**attributes) #

Finds a single record by attributes

  • param : attributes (NamedTuple | Hash(Symbol, DB::Any))
  • return : Target?

[View source]
def first #

Returns the first record in the collection, raises if none found

  • return : Target
  • raise : AssociationNotFound if no records exist

[View source]
def first? #

Returns the first record in the collection

  • return : Target?

[View source]
def ids : Array(Pk) #

Returns a list of primary keys for the associated records

  • return : Array(Pk)

Example

user.posts.ids

[View source]
def ids=(ids : Array(Pk)) #

Associates the parent record with the records that match the primary keys provided

  • param : ids (Array(Pk))
  • return : Array(Target)

Example

user.posts.ids = [1_i64, 2_i64, 3_i64]

[View source]
def includes?(record : Target) : Bool #

Check if the collection includes a specific record

  • param : record (Target)
  • return : Bool

[View source]
def last #

Returns the last record in the collection, raises if none found

  • return : Target
  • raise : AssociationNotFound if no records exist

[View source]
def last? #

Returns the last record in the collection

  • return : Target?

[View source]
def length #

Get the length/size of the collection

  • return : Int32

[View source]
def limit(limit_count : Int32) #

Apply a limit to the query

  • param : limit_count (Int32)
  • return : CQL::Query

[View source]
def loaded? : Bool #

Check if the collection has been loaded

  • return : Bool

[View source]
def map(&block : Target -> U) forall U #

Map over the collection

  • param : block (Block(Target, U))
  • return : Array(U)

[View source]
def map_with_index(&block : Target, Int32 -> U) forall U #

Map with index

  • param : block (Block(Target, Int32, U))
  • return : Array(U)

[View source]
def nullify_all : Int64 #

Set all foreign keys to nil (nullify association)

  • return : Int64 - Number of records updated

[View source]
def offset(offset_count : Int32) #

Apply an offset to the query

  • param : offset_count (Int32)
  • return : CQL::Query

[View source]
def order(**order_by) #

Order the query results, for example user.posts.order(created_at: :desc)

  • param : order_by (column: direction) - each column with :asc or :desc
  • return : CQL::Query

[View source]
def reject(&block : Target -> Bool) #

Reject records matching the given block

  • param : block (Block(Target, Bool))
  • return : Array(Target)

[View source]
def reload #

Reloads the association records from the database

  • return : Array(Target)

Example

user.posts.reload

[View source]
def remove(records : Array(Target)) : Array(Target) #

Remove records from the collection without deleting them

  • param : records (Array(Target))
  • return : Array(Target)

[View source]
def select(&block : Target -> Bool) #

Select records matching the given block

  • param : block (Block(Target, Bool))
  • return : Array(Target)

[View source]
def size #

Returns the number of associated records

  • return : Int32

Example

user.posts.size

[View source]
def to_a #

Convert to array

  • return : Array(Target)

[View source]
def where(__sql sql : String, *positional, **named) #

A raw SQL fragment with bound ? / :name values, scoped to this association.


[View source]
def where(**conditions) #

Returns a new query for chaining where conditions

  • param : conditions (NamedTuple | Hash(Symbol, DB::Any))
  • return : CQL::Query

Example

user.posts.where(title: "Hello").where(published: true).all(Post)

[View source]