class Rotor::HasMany[T <: Rotor::Model]

include Enumerable[T]

A model's has_many association, as its getter gives it (user.posts): the associated models once preloaded (Rotor::Repo#preload), and the query that finds them either way. There is no lazy loading: reading the models of one not preloaded raises Rotor::NotLoadedError.

class HUser < Rotor::Model
  table "users" do
    column :id, Int, primary: true
    has_many HPost, name: :posts, foreign_key: :user_id
  end
end

class HPost < Rotor::Model
  table "posts" do
    column :id, Int, primary: true
    column :user_id, Int
    column :published, Bool, default: false
  end
end

u = HUser.load({id: 7})
u.posts.loaded?  # => false
u.posts.query.to_sql  # => ["SELECT \"id\", \"user_id\", \"published\" FROM \"posts\" WHERE \"user_id\" = $1", [7]]
u.posts.query.where { published }.to_sql[0]  # => "SELECT \"id\", \"user_id\", \"published\" FROM \"posts\" WHERE \"user_id\" = $1 AND \"published\""

/home/runner/work/rotor/rotor/src/association.qz:27

Class methods

def self.new(target: Type[T], owner: String, name: Symbol, foreign_key: Symbol, key_column: Symbol?, key: Int | Float | String | Bool | Time | Bytes | Nil, models: Array[Rotor::Model]?, through: [Type[Object], Rotor::Association]? = …) -> Rotor::HasMany[T]

(Made by the getter has_many generates.)

/home/runner/work/rotor/rotor/src/association.qz:42

def self.foreign_key!(target: Type[Rotor::Model], fk: Symbol, owner: String, name: Symbol) -> Void

Raises unless target has the column fk (an association's key, checked when a query or a preload uses it: the target's table may run after the association's).

/home/runner/work/rotor/rotor/src/association.qz:99

Methods

def loaded? -> Bool

Whether the models were preloaded.

/home/runner/work/rotor/rotor/src/association.qz:46

def target -> Type[T]

The associated model's class.

/home/runner/work/rotor/rotor/src/association.qz:49

def each(&: (T) -> Void) -> Void

Calls the block with each model; raises Rotor::NotLoadedError when they were not preloaded.

/home/runner/work/rotor/rotor/src/association.qz:53

def size -> Int

How many models there are (preloaded).

/home/runner/work/rotor/rotor/src/association.qz:58

def empty? -> Bool

Whether there is none (preloaded).

/home/runner/work/rotor/rotor/src/association.qz:61

def to_a -> Array[T]

The models, in an array (preloaded).

/home/runner/work/rotor/rotor/src/association.qz:64

def query -> Rotor::Query[T]

The association as a query: the target's rows whose foreign key is this model's key, to refine (posts.query.where { published }) and run (repo.all(user.posts.query)); through a join model, the target's rows the join model's rows pair with this one, by a subquery ("id" IN (SELECT "tag_id" FROM "post_tags" WHERE "post_id" = $1): each once). Raises Rotor::SchemaError when the target has no such column (or the join model no such belongs_to), Rotor::MissingAttributeError when the model's key is not set.

/home/runner/work/rotor/rotor/src/association.qz:74

def inspect -> String

A developer-readable representation, as p prints it: strings quoted, collections with their elements' inspect, an object with its fields (#<Point @x=1, @y=2>).

from Object

/home/runner/work/rotor/rotor/src/association.qz:86

def to_s -> String

The value as a string, for puts and interpolation. For an instance of a class, the class name in the form #<Point>; for an exception, its message; for a data value or an enum variant, the default inspect. It does not call an inspect the class defines.

from Object

/home/runner/work/rotor/rotor/src/association.qz:94