Module: ActiveRecord::Refined::QueryMethods
- Defined in:
- lib/active_record/refined.rb
Instance Method Summary collapse
-
#cross_joins(*args, as: nil, &block) ⇒ Object
CROSS JOIN: every row of one table against every row of the other, so unlike the joins above there is no condition to give and no block to write it in.
-
#distinct_on(*columns, &block) ⇒ Object
DISTINCT ON (...), which keeps the first row of each group the order brings up.
- #distinct_on!(*columns, &block) ⇒ Object
-
#distinct_on_values ⇒ Object
Active Record generates these for the values it knows about; this one is ours, and lives in the same place so that it survives a spawn.
- #distinct_on_values=(columns) ⇒ Object
-
#from(value, subquery_name = nil, as: nil) ⇒ Object
A symbol names a table, which Active Record's own from only takes as a string.
-
#from_cte(name) ⇒ Object
Selects a CTE in place of the model's own table.
- #from_cte_value ⇒ Object
- #from_cte_value=(name) ⇒ Object
- #full_outer_joins(*args, as: nil, &block) ⇒ Object
- #group(*args, &block) ⇒ Object
- #having(opts = nil, *rest, &block) ⇒ Object
-
#joins(*args, as: nil, &block) ⇒ Object
asnames the table within the query, which is what makes a self join expressible: joins(:employees, as: :managers) { ... }. -
#lateral ⇒ Object
Marks the relation for a lateral join, which lets it see the row being joined to -- the top few rows of each group, and the like.
- #lateral! ⇒ Object
- #lateral_value ⇒ Object
- #lateral_value=(value) ⇒ Object
- #left_outer_joins(*args, as: nil, &block) ⇒ Object
- #order(*args, &block) ⇒ Object
-
#right_outer_joins(*args, as: nil, &block) ⇒ Object
The other two outer joins, which Active Record has no method for and Arel has the nodes for.
- #select(*fields, &block) ⇒ Object
- #where(opts = nil, *rest, &block) ⇒ Object
Instance Method Details
#cross_joins(*args, as: nil, &block) ⇒ Object
CROSS JOIN: every row of one table against every row of the other, so unlike the joins above there is no condition to give and no block to write it in.
Post.cross_joins(:authors)
Post.cross_joins(:posts, as: :others)
514 515 516 517 518 519 520 |
# File 'lib/active_record/refined.rb', line 514 def cross_joins(*args, as: nil, &block) if block raise ArgumentError, 'a cross join has no condition; joins is the one that takes a block' end joins(build_cross_join(args.first, as)) end |
#distinct_on(*columns, &block) ⇒ Object
DISTINCT ON (...), which keeps the first row of each group the order brings up. PostgreSQL has it and the others do not; Arel carries the node and refuses to write it elsewhere, the way it does a regexp, so there is nothing for this to check:
Post.distinct_on { :author }.order { [:author, :likes.desc] }
The portable shape is a row_number window in a subquery, which the README shows.
422 423 424 |
# File 'lib/active_record/refined.rb', line 422 def distinct_on(*columns, &block) spawn.distinct_on!(*columns, &block) end |
#distinct_on!(*columns, &block) ⇒ Object
426 427 428 429 430 431 432 433 |
# File 'lib/active_record/refined.rb', line 426 def distinct_on!(*columns, &block) columns = Array(evaluate_block(&block)) if block if columns.empty? raise ArgumentError, "distinct_on needs a column or an expression" end self.distinct_on_values += columns self end |
#distinct_on_values ⇒ Object
Active Record generates these for the values it knows about; this one is ours, and lives in the same place so that it survives a spawn.
437 438 439 |
# File 'lib/active_record/refined.rb', line 437 def distinct_on_values @values.fetch(:distinct_on, ActiveRecord::QueryMethods::FROZEN_EMPTY_ARRAY) end |
#distinct_on_values=(columns) ⇒ Object
441 442 443 444 |
# File 'lib/active_record/refined.rb', line 441 def distinct_on_values=(columns) assert_modifiable! @values[:distinct_on] = columns end |
#from(value, subquery_name = nil, as: nil) ⇒ Object
A symbol names a table, which Active Record's own from only takes as a
string. With as it is selected under another name; when that name
is the model's own, from_cte says the same thing without repeating it.
373 374 375 376 377 378 379 380 381 382 383 |
# File 'lib/active_record/refined.rb', line 373 def from(value, subquery_name = nil, as: nil) unless value.is_a?(Symbol) if as raise ArgumentError, "as: needs the table named as a symbol" end return super(value, subquery_name) end arel_table = Arel::Table.new(value) arel_table = arel_table.alias(as) if as super(arel_table, subquery_name) end |
#from_cte(name) ⇒ Object
Selects a CTE in place of the model's own table. The alias is not a choice -- Active Record keeps qualifying columns with the table name, so the model's is the only name that works -- which is why it is taken from the model rather than asked for: with_recursive(tree: [...]).from_cte(:tree)
The name is checked against what with declares, so that a typo is
not a query against a table nobody has. Checked when the SQL is
built, since the CTE may be declared after this in the chain, or by a
scope merged into it.
395 396 397 398 399 400 401 402 |
# File 'lib/active_record/refined.rb', line 395 def from_cte(name) unless name.is_a?(Symbol) raise ArgumentError, "from_cte takes the CTE's name as a symbol" end relation = from(name, as: klass.table_name) relation.from_cte_value = name relation end |
#from_cte_value ⇒ Object
404 405 406 |
# File 'lib/active_record/refined.rb', line 404 def from_cte_value @values[:from_cte] end |
#from_cte_value=(name) ⇒ Object
408 409 410 411 |
# File 'lib/active_record/refined.rb', line 408 def from_cte_value=(name) assert_modifiable! @values[:from_cte] = name end |
#full_outer_joins(*args, as: nil, &block) ⇒ Object
502 503 504 505 506 |
# File 'lib/active_record/refined.rb', line 502 def full_outer_joins(*args, as: nil, &block) check_full_outer_support outer_joins(:full_outer_joins, Arel::Nodes::FullOuterJoin, args, as, &block) end |
#group(*args, &block) ⇒ Object
360 361 362 363 364 365 366 367 368 |
# File 'lib/active_record/refined.rb', line 360 def group(*args, &block) if block result = evaluate_block(&block) arel = Array(result).map {|node| to_arel_field(node) } super(*arel, &nil) else super end end |
#having(opts = nil, *rest, &block) ⇒ Object
342 343 344 345 346 347 348 |
# File 'lib/active_record/refined.rb', line 342 def having(opts = nil, *rest, &block) if block super(evaluate_block(&block).to_arel(table, klass)) else super end end |
#joins(*args, as: nil, &block) ⇒ Object
as names the table within the query, which is what makes a self
join expressible: joins(:employees, as: :managers) { ... }.
470 471 472 473 474 475 476 477 478 479 |
# File 'lib/active_record/refined.rb', line 470 def joins(*args, as: nil, &block) if args.first.is_a?(ActiveRecord::Relation) super(build_lateral_join(args.first, Arel::Nodes::InnerJoin, as, &block)) elsif block super(build_join_node(args.first, Arel::Nodes::InnerJoin, as, &block)) else reject_join_alias(as) super(*args, &block) end end |
#lateral ⇒ Object
Marks the relation for a lateral join, which lets it see the row being joined to -- the top few rows of each group, and the like. In SQL the keyword modifies the subquery, not the join, so it is said on the relation: left_outer_joins(top_post.lateral, as: :top).
450 451 452 |
# File 'lib/active_record/refined.rb', line 450 def lateral spawn.lateral! end |
#lateral! ⇒ Object
454 455 456 457 |
# File 'lib/active_record/refined.rb', line 454 def lateral! self.lateral_value = true self end |
#lateral_value ⇒ Object
459 460 461 |
# File 'lib/active_record/refined.rb', line 459 def lateral_value @values[:lateral] end |
#lateral_value=(value) ⇒ Object
463 464 465 466 |
# File 'lib/active_record/refined.rb', line 463 def lateral_value=(value) assert_modifiable! @values[:lateral] = value end |
#left_outer_joins(*args, as: nil, &block) ⇒ Object
481 482 483 484 485 486 487 488 489 490 |
# File 'lib/active_record/refined.rb', line 481 def left_outer_joins(*args, as: nil, &block) if args.first.is_a?(ActiveRecord::Relation) joins(build_lateral_join(args.first, Arel::Nodes::OuterJoin, as, &block)) elsif block joins(build_join_node(args.first, Arel::Nodes::OuterJoin, as, &block)) else reject_join_alias(as) super(*args, &block) end end |
#order(*args, &block) ⇒ Object
350 351 352 353 354 355 356 357 358 |
# File 'lib/active_record/refined.rb', line 350 def order(*args, &block) if block result = evaluate_block(&block) arel = Array(result).map {|node| to_arel_field(node) } super(*arel, &nil) else super end end |
#right_outer_joins(*args, as: nil, &block) ⇒ Object
The other two outer joins, which Active Record has no method for and
Arel has the nodes for. The rules are joins': the block is the ON,
as names the table within the query, a relation marked lateral
joins as one. An association name is not among them -- what Active
Record reads out of one is an inner or a left join and nothing else.
497 498 499 500 |
# File 'lib/active_record/refined.rb', line 497 def right_outer_joins(*args, as: nil, &block) outer_joins(:right_outer_joins, Arel::Nodes::RightOuterJoin, args, as, &block) end |
#select(*fields, &block) ⇒ Object
332 333 334 335 336 337 338 339 340 |
# File 'lib/active_record/refined.rb', line 332 def select(*fields, &block) if block result = evaluate_block(&block) arel = Array(result).map {|node| to_arel_field(node) } super(*arel, &nil) else super end end |
#where(opts = nil, *rest, &block) ⇒ Object
324 325 326 327 328 329 330 |
# File 'lib/active_record/refined.rb', line 324 def where(opts = nil, *rest, &block) if block super(evaluate_block(&block).to_arel(table, klass)) else super end end |