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)
556 557 558 559 560 561 562 |
# File 'lib/active_record/refined.rb', line 556 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.
464 465 466 |
# File 'lib/active_record/refined.rb', line 464 def distinct_on(*columns, &block) spawn.distinct_on!(*columns, &block) end |
#distinct_on!(*columns, &block) ⇒ Object
468 469 470 471 472 473 474 475 |
# File 'lib/active_record/refined.rb', line 468 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.
479 480 481 |
# File 'lib/active_record/refined.rb', line 479 def distinct_on_values @values.fetch(:distinct_on, ActiveRecord::QueryMethods::FROZEN_EMPTY_ARRAY) end |
#distinct_on_values=(columns) ⇒ Object
483 484 485 486 |
# File 'lib/active_record/refined.rb', line 483 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.
415 416 417 418 419 420 421 422 423 424 425 |
# File 'lib/active_record/refined.rb', line 415 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.
437 438 439 440 441 442 443 444 |
# File 'lib/active_record/refined.rb', line 437 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
446 447 448 |
# File 'lib/active_record/refined.rb', line 446 def from_cte_value @values[:from_cte] end |
#from_cte_value=(name) ⇒ Object
450 451 452 453 |
# File 'lib/active_record/refined.rb', line 450 def from_cte_value=(name) assert_modifiable! @values[:from_cte] = name end |
#full_outer_joins(*args, as: nil, &block) ⇒ Object
544 545 546 547 548 |
# File 'lib/active_record/refined.rb', line 544 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
402 403 404 405 406 407 408 409 410 |
# File 'lib/active_record/refined.rb', line 402 def group(*args, &block) if block result = evaluate_block(&block) check_rollup_stands_alone(result) super(*to_arel_fields(result), &nil) else super end end |
#having(opts = nil, *rest, &block) ⇒ Object
386 387 388 389 390 391 392 |
# File 'lib/active_record/refined.rb', line 386 def having(opts = nil, *rest, &block) if block super(to_arel_condition(evaluate_block(&block))) 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) { ... }.
512 513 514 515 516 517 518 519 520 521 |
# File 'lib/active_record/refined.rb', line 512 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).
492 493 494 |
# File 'lib/active_record/refined.rb', line 492 def lateral spawn.lateral! end |
#lateral! ⇒ Object
496 497 498 499 |
# File 'lib/active_record/refined.rb', line 496 def lateral! self.lateral_value = true self end |
#lateral_value ⇒ Object
501 502 503 |
# File 'lib/active_record/refined.rb', line 501 def lateral_value @values[:lateral] end |
#lateral_value=(value) ⇒ Object
505 506 507 508 |
# File 'lib/active_record/refined.rb', line 505 def lateral_value=(value) assert_modifiable! @values[:lateral] = value end |
#left_outer_joins(*args, as: nil, &block) ⇒ Object
523 524 525 526 527 528 529 530 531 532 |
# File 'lib/active_record/refined.rb', line 523 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
394 395 396 397 398 399 400 |
# File 'lib/active_record/refined.rb', line 394 def order(*args, &block) if block super(*to_arel_fields(evaluate_block(&block)), &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.
539 540 541 542 |
# File 'lib/active_record/refined.rb', line 539 def right_outer_joins(*args, as: nil, &block) outer_joins(:right_outer_joins, Arel::Nodes::RightOuterJoin, args, as, &block) end |
#select(*fields, &block) ⇒ Object
378 379 380 381 382 383 384 |
# File 'lib/active_record/refined.rb', line 378 def select(*fields, &block) if block super(*to_arel_fields(evaluate_block(&block)), &nil) else super end end |
#where(opts = nil, *rest, &block) ⇒ Object
370 371 372 373 374 375 376 |
# File 'lib/active_record/refined.rb', line 370 def where(opts = nil, *rest, &block) if block super(to_arel_condition(evaluate_block(&block))) else super end end |