Class: Query

Inherits:
Object
  • Object
show all
Defined in:
lib/lilit_sql.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(froms, conditions = [], grouped_keys = [], order_bys = [], row = nil, limit = nil, offset = nil) ⇒ Query

Returns a new instance of Query.



399
400
401
402
403
404
405
406
407
408
# File 'lib/lilit_sql.rb', line 399

def initialize(froms, conditions = [], grouped_keys = [], order_bys = [], row = nil, limit = nil, offset = nil)
  @froms = froms + []
  @conditions = conditions + []
  @grouped_keys = grouped_keys + []
  @order_bys = order_bys + []
  @row = row
  @_limit = limit
  @_offset = offset
  @subquery_name = nil
end

Instance Attribute Details

#_limitObject

Returns the value of attribute _limit.



397
398
399
# File 'lib/lilit_sql.rb', line 397

def _limit
  @_limit
end

#_offsetObject

Returns the value of attribute _offset.



397
398
399
# File 'lib/lilit_sql.rb', line 397

def _offset
  @_offset
end

#conditionsObject

Returns the value of attribute conditions.



397
398
399
# File 'lib/lilit_sql.rb', line 397

def conditions
  @conditions
end

#fromsObject

Returns the value of attribute froms.



397
398
399
# File 'lib/lilit_sql.rb', line 397

def froms
  @froms
end

#grouped_keysObject

Returns the value of attribute grouped_keys.



397
398
399
# File 'lib/lilit_sql.rb', line 397

def grouped_keys
  @grouped_keys
end

#order_bysObject

Returns the value of attribute order_bys.



397
398
399
# File 'lib/lilit_sql.rb', line 397

def order_bys
  @order_bys
end

#rowObject

Returns the value of attribute row.



397
398
399
# File 'lib/lilit_sql.rb', line 397

def row
  @row
end

#subquery_nameObject

Raises:

  • (ArgumentError)


533
534
535
536
537
538
539
# File 'lib/lilit_sql.rb', line 533

def subquery_name
  return @froms.first.source.subquery_name if is_vanilla

  raise ArgumentError, "The query #{inspect} doesn't have a subquery name" if @subquery_name.nil?

  @subquery_name
end

Class Method Details

.from(query) ⇒ Object



410
411
412
# File 'lib/lilit_sql.rb', line 410

def self.from(query)
  new([From.new(query)])
end

Instance Method Details

#cross_join(other) ⇒ Object



501
502
503
# File 'lib/lilit_sql.rb', line 501

def cross_join(other)
  perform_join(:cross_join, other)
end

#cross_join_unnest(ordinality = false, &blk) ⇒ Object



505
506
507
508
509
510
511
512
513
514
515
516
# File 'lib/lilit_sql.rb', line 505

def cross_join_unnest(ordinality = false, &blk)
  return Query.from(self).cross_join_unnest(ordinality, &blk) if @row || @conditions.size.positive? || @order_bys.size.positive? || @_limit || @_offset

  result = expr(&blk).call(*get_from_rows)
  row = Row.new(result.class.members, result)
  from = CrossJoinUnnest.new(From.new(Table.new(result.class, 't')), row, ordinality)
  Query.new(
    @froms + [from],
    @conditions,
    @grouped_keys,
  )
end

#group_by(&blk) ⇒ Object



475
476
477
478
479
480
481
482
483
484
485
486
487
# File 'lib/lilit_sql.rb', line 475

def group_by(&blk)
  return Query.from(self).group_by(&blk) if @row

  result = expr(&blk).call(*get_from_rows)

  if result.is_a?(Column)
    GroupBy.new(self, [result])
  elsif result.is_a?(Array)
    GroupBy.new(self, result)
  else
    raise NotImplementedError
  end
end

#has?(column_name) ⇒ Boolean

Returns:

  • (Boolean)


433
434
435
# File 'lib/lilit_sql.rb', line 433

def has?(column_name)
  rows.any? { |r| r.has?(column_name) }
end

#is_vanillaObject



414
415
416
# File 'lib/lilit_sql.rb', line 414

def is_vanilla
  @froms.size == 1 && @conditions.empty? && @grouped_keys.empty? && @row.nil?
end

#join(other, &blk) ⇒ Object



489
490
491
# File 'lib/lilit_sql.rb', line 489

def join(other, &blk)
  perform_join(:join, other, &blk)
end

#left_join(other, &blk) ⇒ Object



493
494
495
# File 'lib/lilit_sql.rb', line 493

def left_join(other, &blk)
  perform_join(:left_join, other, &blk)
end

#limit(number) ⇒ Object



465
466
467
468
# File 'lib/lilit_sql.rb', line 465

def limit(number)
  @_limit = number
  self
end

#map(&blk) ⇒ Object



418
419
420
421
422
423
424
425
426
427
428
429
430
431
# File 'lib/lilit_sql.rb', line 418

def map(&blk)
  return Query.from(self).map(&blk) if @row

  result = expr(&blk).call(*get_from_rows)
  Query.new(
    @froms,
    @conditions,
    @grouped_keys,
    @order_bys,
    Row.new(result.class.members, result),
    @_limit,
    @_offset
  )
end

#offset(number) ⇒ Object



470
471
472
473
# File 'lib/lilit_sql.rb', line 470

def offset(number)
  @_offset = number
  self
end

#order_by(&blk) ⇒ Object



443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
# File 'lib/lilit_sql.rb', line 443

def order_by(&blk)
  return Query.from(self).order_by(&blk) if @row

  result = expr(&blk).call(*get_from_rows)

  if result.is_a?(OrderedByExpr)
    result = [result]
  elsif result.is_a?(Expr)
    result = OrderedByExpr.new(result)
  end

  Query.new(
    @froms,
    @conditions,
    @grouped_keys,
    @order_bys + result,
    @row,
    @_limit,
    @_offset
  )
end

#right_join(other, &blk) ⇒ Object



497
498
499
# File 'lib/lilit_sql.rb', line 497

def right_join(other, &blk)
  perform_join(:right_join, other, &blk)
end

#rowsObject



437
438
439
440
441
# File 'lib/lilit_sql.rb', line 437

def rows
  return [@row] if @row

  get_from_rows
end

#sqlObject



543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
# File 'lib/lilit_sql.rb', line 543

def sql
  s = 'select '
  s += rows.map(&:decl_sql).join(', ')
  s += ' from'

  @froms.each_with_index do |from, index|
    if from.is_a?(From)
      if index >= 1
        if from.join_type == :join
          s += ' join'
        elsif from.join_type == :left_join
          s += ' left join'
        elsif from.join_type == :right_join
          s += ' right join'
        elsif from.join_type == :cross_join
          s += ' cross join'
        else
          raise ArgumentError, "The join type #{from.join_type} is not supoprted."
        end
      end

      s += " #{from.source.subquery_name}"

      s += " #{from.alias_name}" if from.source.subquery_name != from.alias_name

      s += " on #{from.condition.ref_sql}" if from.condition
    elsif from.is_a?(CrossJoinUnnest)
      origins, cols = from.rows.first.columns.map {|c| [c.origin.ref_sql, c.name]}.transpose
      s += " cross join unnest (#{origins.join(', ')})"
      if from.ordinality
        s += ' with ordinality'
        cols.push('ordinal')
      end
      s += " as #{from.from.source.table_name} (#{cols.join(', ')})"
    else
      raise ArgumentError.new("From doesn't support #{from.inspect}")
    end
  end

  s += " where #{@conditions.map(&:ref_sql).join(' and ')}" if @conditions.size.positive?

  s += " group by #{@grouped_keys.map(&:ref_sql).join(', ')}" if @grouped_keys.size.positive?

  s += " order by #{@order_bys.map(&:sql).join(', ')}" if @order_bys.size.positive?

  if @_offset
    s += " offset #{@_offset}"
  end

  if @_limit
    s += " limit #{@_limit}"
  end

  s
end

#where(&blk) ⇒ Object



518
519
520
521
522
523
524
525
526
527
528
529
530
531
# File 'lib/lilit_sql.rb', line 518

def where(&blk)
  return Query.from(self).where(&blk) if @row

  condition = expr(&blk).call(*get_from_rows)
  Query.new(
    @froms,
    @conditions + [condition],
    @grouped_keys,
    @order_bys,
    @row,
    @_limit,
    @_offset
  )
end