Class: Bmg::Sequel::Translator

Inherits:
Sexpr::Processor
  • Object
show all
Includes:
Predicate::ToSequel::Methods
Defined in:
lib/bmg/sequel/translator.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(sequel_db) ⇒ Translator

Returns a new instance of Translator.



6
7
8
# File 'lib/bmg/sequel/translator.rb', line 6

def initialize(sequel_db)
  @sequel_db = sequel_db
end

Instance Attribute Details

#sequel_dbObject (readonly)

Returns the value of attribute sequel_db.



9
10
11
# File 'lib/bmg/sequel/translator.rb', line 9

def sequel_db
  @sequel_db
end

Instance Method Details

#compile_predicate(predicate) ⇒ Object



184
185
186
# File 'lib/bmg/sequel/translator.rb', line 184

def compile_predicate(predicate)
  PredicateTranslator.new(self).call(predicate)
end

#on_column_name(sexpr) ⇒ Object



111
112
113
# File 'lib/bmg/sequel/translator.rb', line 111

def on_column_name(sexpr)
  ::Sequel.expr(sexpr.last.to_sym)
end

#on_from_clause(sexpr) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/bmg/sequel/translator.rb', line 115

def on_from_clause(sexpr)
  orderer = Sql::Support::FromClauseOrderer.new
  ordering = orderer.call(sexpr)
  ordering.inject(nil) do |ds,(kind,table,on)|
    if ds.nil?
      dataset(apply(table))
    elsif kind == :cross_join
      ds.cross_join(apply(table))
    elsif kind == :inner_join
      options = { qualify: false, table_alias: false }
      ds.join_table(:inner, apply(table), nil, options){|*args|
        compile_predicate(on)
      }
    elsif kind == :left_join
      options = { qualify: false, table_alias: false }
      ds.join_table(:left, apply(table), nil, options){|*args|
        compile_predicate(on)
      }
    else
      raise IllegalArgumentError, "Unrecognized from clause: `#{sexpr}`"
    end
  end
end

#on_func_call(sexpr) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/bmg/sequel/translator.rb', line 80

def on_func_call(sexpr)
  case sexpr.func_name
  when :cast
    to_cast = apply(sexpr.func_args.first)
    to_cast = ::Sequel.expr(nil) if to_cast.nil?
    type = sexpr.func_args.last.last
    to_cast.cast(type)
  else
    args = sexpr.func_args.map{|fa| apply(fa) }
    ::Sequel.function(sexpr.func_name, *args)
  end
end

#on_group_by_clause(sexpr) ⇒ Object



161
162
163
164
# File 'lib/bmg/sequel/translator.rb', line 161

def on_group_by_clause(sexpr)
  return nil unless sexpr.size > 1
  sexpr.sexpr_body.map{|c| apply(c)}
end

#on_limit_clause(sexpr) ⇒ Object



174
175
176
# File 'lib/bmg/sequel/translator.rb', line 174

def on_limit_clause(sexpr)
  sexpr.last
end

#on_native_table_as(sexpr) ⇒ Object



143
144
145
# File 'lib/bmg/sequel/translator.rb', line 143

def on_native_table_as(sexpr)
  sexpr[1].from_self(:alias => sexpr.as_name)
end

#on_offset_clause(sexpr) ⇒ Object



178
179
180
# File 'lib/bmg/sequel/translator.rb', line 178

def on_offset_clause(sexpr)
  sexpr.last
end

#on_order_by_clause(sexpr) ⇒ Object



166
167
168
# File 'lib/bmg/sequel/translator.rb', line 166

def on_order_by_clause(sexpr)
  sexpr.sexpr_body.map{|c| apply(c)}
end

#on_order_by_term(sexpr) ⇒ Object



170
171
172
# File 'lib/bmg/sequel/translator.rb', line 170

def on_order_by_term(sexpr)
  ::Sequel.send(sexpr.direction, apply(sexpr.qualified_name))
end

#on_qualified_name(sexpr) ⇒ Object



107
108
109
# File 'lib/bmg/sequel/translator.rb', line 107

def on_qualified_name(sexpr)
  apply(sexpr.last).qualify(sexpr.qualifier)
end

#on_select_exp(sexpr) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/bmg/sequel/translator.rb', line 39

def on_select_exp(sexpr)
  dataset   = sequel_db.select(1)
  dataset   = apply(sexpr.from_clause)     if sexpr.from_clause
  #
  selection = apply(sexpr.select_list)
  predicate = compile_predicate(sexpr.predicate) if sexpr.predicate
  grouping  = apply(sexpr.group_by_clause) if sexpr.group_by_clause
  order     = apply(sexpr.order_by_clause) if sexpr.order_by_clause
  limit     = apply(sexpr.limit_clause)    if sexpr.limit_clause
  offset    = apply(sexpr.offset_clause)   if sexpr.offset_clause
  #
  dataset   = dataset.select(*selection)
  dataset   = dataset.distinct             if sexpr.distinct?
  dataset   = dataset.where(predicate)     if predicate
  dataset   = dataset.group(*grouping)     if grouping
  dataset   = dataset.order_by(*order)     if order
  dataset   = dataset.limit(limit, offset == 0 ? nil : offset) if limit or offset
  dataset
end

#on_select_item(sexpr) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/bmg/sequel/translator.rb', line 67

def on_select_item(sexpr)
  left  = apply(sexpr.left)
  right = apply(sexpr.right)
  case kind = sexpr.left.first
  when :qualified_name
    left.column == right.value ? left : ::Sequel.as(left, right)
  when :literal, :summarizer, :func_call
    ::Sequel.as(left, right)
  else
    raise NotImplementedError, "Unexpected select item `#{kind}`"
  end
end

#on_select_list(sexpr) ⇒ Object



59
60
61
# File 'lib/bmg/sequel/translator.rb', line 59

def on_select_list(sexpr)
  sexpr.sexpr_body.map{|c| apply(c) }
end

#on_select_star(sexpr) ⇒ Object



63
64
65
# File 'lib/bmg/sequel/translator.rb', line 63

def on_select_star(sexpr)
  ::Sequel.lit('*')
end

#on_set_operator(sexpr) ⇒ Object Also known as: on_union, on_intersect, on_except



30
31
32
33
34
# File 'lib/bmg/sequel/translator.rb', line 30

def on_set_operator(sexpr)
  sexpr.tail_exprs.inject(apply(sexpr.head_expr)) do |left,right|
    left.send(sexpr.first, apply(right), all: sexpr.all?, from_self: false)
  end
end

#on_subquery_as(sexpr) ⇒ Object



157
158
159
# File 'lib/bmg/sequel/translator.rb', line 157

def on_subquery_as(sexpr)
  ::Sequel.as(apply(sexpr.subquery), ::Sequel.identifier(sexpr.as_name))
end

#on_summarizer(sexpr) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/bmg/sequel/translator.rb', line 93

def on_summarizer(sexpr)
  func, distinct = if sexpr.summary_func == :distinct_count
    [:count, true]
  else
    [sexpr.summary_func, false]
  end
  f = if sexpr.summary_expr
    ::Sequel.function(func, apply(sexpr.summary_expr))
  else
    ::Sequel.function(func).*
  end
  distinct ? f.distinct : f
end

#on_table_as(sexpr) ⇒ Object



147
148
149
150
151
152
153
154
155
# File 'lib/bmg/sequel/translator.rb', line 147

def on_table_as(sexpr)
  table_name = case sexpr.table_name
  when String, Symbol then ::Sequel.expr(sexpr.table_name.to_sym)
  when ::Sequel::SQL::QualifiedIdentifier then sexpr.table_name
  else
    raise ArgumentError, "Invalid table name `#{sexpr.table_name}`"
  end
  ::Sequel.as(table_name, ::Sequel.identifier(sexpr.as_name))
end

#on_table_name(sexpr) ⇒ Object



139
140
141
# File 'lib/bmg/sequel/translator.rb', line 139

def on_table_name(sexpr)
  ::Sequel.expr(sexpr.last.to_sym)
end

#on_with_exp(sexpr) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
# File 'lib/bmg/sequel/translator.rb', line 11

def on_with_exp(sexpr)
  if sequel_db.select(1).supports_cte?
    dataset = apply(sexpr.select_exp)
    apply(sexpr.with_spec).each_pair do |name, subquery|
      dataset = dataset.with(name, subquery)
    end
    dataset
  else
    apply(Sql::Processor::Flatten.new(Sql::Builder.new).call(sexpr))
  end
end

#on_with_spec(sexpr) ⇒ Object



23
24
25
26
27
28
# File 'lib/bmg/sequel/translator.rb', line 23

def on_with_spec(sexpr)
  sexpr.each_with_object({}){|child,hash|
    next if child == :with_spec
    hash[apply(child.table_name)] = apply(child.subquery)
  }
end