Module: GoogleDataSource::DataSource::Sql::Parser

Extended by:
Parsers
Includes:
Functors, Parsers, RParsec
Included in:
GoogleDataSource::DataSource::SqlParser
Defined in:
lib/google_data_source/sql/parser.rb

Constant Summary collapse

MyKeywords =

TODO drop keywords

Keywords.case_insensitive(%w{
  select from where group by having order desc asc
  inner left right full outer inner join on cross
  union all distinct as exists in between limit offset
  case when else end and or not true false
})
MyOperators =
Operators.new(%w{+ - * / % = > < >= <= <> != : ( ) . ,})
Comparators =
operators(*%w{= > < >= <= <> !=})
StringLiteral =
char(?') >> ((str("\\\\")|str("\\'")|not_char(?')).many_.fragment).map(&quote_mapper) << char(?')
QuotedName =
char(?`) >> not_char(?`).many_.fragment << char(?`)
Variable =
char(?$) >> word
MyLexer =
number.token(:number) | StringLiteral.token(:string) | Variable.token(:var) |
QuotedName.token(:word) | MyKeywords.lexer | MyOperators.lexer
MyLexeme =
MyLexer.lexeme(whitespaces | comment_line('#')) << eof

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.operators(*ops) ⇒ Object



21
22
23
24
25
26
27
# File 'lib/google_data_source/sql/parser.rb', line 21

def self.operators(*ops)
  result = []
  ops.each do |op|
    result << (MyOperators[op] >> op.to_sym)
  end
  sum(*result)
end

Instance Method Details

#assembleObject



222
223
224
225
226
227
228
229
230
231
# File 'lib/google_data_source/sql/parser.rb', line 222

def assemble
  pred = nil
  rel = nil
  lazy_predicate = lazy{pred}
  lazy_rel = lazy{rel}
  expr = make_expression lazy_predicate, lazy_rel
  pred = make_predicate expr, lazy_rel
  rel = make_relation expr, pred
  return expr, pred, rel
end

#calculate_full_cases(cases, default) ⇒ Object



161
162
163
# File 'lib/google_data_source/sql/parser.rb', line 161

def calculate_full_cases(cases, default)
  CaseExpr.new(cases, default)
end

#calculate_simple_cases(val, cases, default) ⇒ Object

expression parser ###############################



157
158
159
# File 'lib/google_data_source/sql/parser.rb', line 157

def calculate_simple_cases(val, cases, default)
  SimpleCaseExpr.new(val, cases, default)
end

#commaObject



51
52
53
# File 'lib/google_data_source/sql/parser.rb', line 51

def comma
  operator[',']
end

#ctor(cls) ⇒ Object



71
72
73
# File 'lib/google_data_source/sql/parser.rb', line 71

def ctor cls
  cls.method :new
end

#expressionObject

put together ###############################



211
212
213
# File 'lib/google_data_source/sql/parser.rb', line 211

def expression
  assemble[0]
end

#keywordObject

utilities #########################################



43
44
45
# File 'lib/google_data_source/sql/parser.rb', line 43

def keyword
  MyKeywords
end

#list(expr) ⇒ Object



55
56
57
# File 'lib/google_data_source/sql/parser.rb', line 55

def list expr
  paren(expr.delimited(comma))
end

#logical_operator(op) ⇒ Object

predicate parser #############################



80
81
82
# File 'lib/google_data_source/sql/parser.rb', line 80

def logical_operator op
  proc{|a,b|CompoundPredicate.new(a,op,b)}
end

#make(parser) ⇒ Object



233
234
235
# File 'lib/google_data_source/sql/parser.rb', line 233

def make parser
  MyLexeme.nested(parser << eof)
end

#make_between(expr) ⇒ Object



124
125
126
# File 'lib/google_data_source/sql/parser.rb', line 124

def make_between expr
  make_between_clause(expr, &ctor(BetweenPredicate))
end

#make_between_clause(expr, &maker) ⇒ Object



147
148
149
150
151
152
153
154
# File 'lib/google_data_source/sql/parser.rb', line 147

def make_between_clause expr, &maker
  factory = proc do |a,_,b|
    proc {|v|maker.call(v,a,b)}
  end
  variant1 = keyword[:between] >> paren(sequence(expr, comma, expr, &factory))
  variant2 = keyword[:between] >> sequence(expr, keyword[:and], expr, &factory)
  variant1 | variant2
end

#make_comparison_predicate(expr, rel) ⇒ Object



132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/google_data_source/sql/parser.rb', line 132

def make_comparison_predicate expr, rel
  comparison = sequence(Comparators, expr) do |op,e2|
    proc{|e1|ComparePredicate.new(e1, op, e2)}
  end
  in_clause = make_in expr
  not_in_clause = make_not_in expr
  in_relation = make_in_relation rel
  not_in_relation = make_not_in_relation rel
  between = make_between expr
  not_between = make_not_between expr
  compare_with = comparison | in_clause | not_in_clause |
      in_relation | not_in_relation | between | not_between
  sequence(expr, compare_with, &Feed)
end

#make_exists(rel) ⇒ Object



100
101
102
# File 'lib/google_data_source/sql/parser.rb', line 100

def make_exists rel
  keyword[:exists] >> rel.map(&ctor(ExistsPredicate))
end

#make_expression(predicate, rel) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/google_data_source/sql/parser.rb', line 165

def make_expression predicate, rel
  expr = nil
  lazy_expr = lazy{expr}

  wildcard = operator[:*] >> WildcardExpr::Instance
  lit = token(:number, :string, &ctor(LiteralExpr)) | token(:var, &ctor(VarExpr))
  atom = lit | wildcard | word(&ctor(WordExpr))
  term = atom | (operator['('] >> lazy_expr << operator[')'])

  table = OperatorTable.new.
    infixl(operator['+'] >> Plus, 20).
    infixl(operator['-'] >> Minus, 20).
    infixl(operator['*'] >> Mul, 30).
    infixl(operator['/'] >> Div, 30).
    infixl(operator['%'] >> Mod, 30).
    prefix(operator['-'] >> Neg, 50)
  expr = Expressions.build(term, table)
end

#make_in(expr) ⇒ Object



108
109
110
# File 'lib/google_data_source/sql/parser.rb', line 108

def make_in expr
  keyword[:in] >> list(expr) >> map(&rctor(InPredicate))
end

#make_in_relation(rel) ⇒ Object



116
117
118
# File 'lib/google_data_source/sql/parser.rb', line 116

def make_in_relation rel
  keyword[:in] >> rel.map(&rctor(InRelationPredicate))
end

#make_not_between(expr) ⇒ Object



128
129
130
# File 'lib/google_data_source/sql/parser.rb', line 128

def make_not_between expr
  keyword[:not] >> make_between_clause(expr, &ctor(NotBetweenPredicate))
end

#make_not_exists(rel) ⇒ Object



104
105
106
# File 'lib/google_data_source/sql/parser.rb', line 104

def make_not_exists rel
  keyword[:not] >> keyword[:exists] >> rel.map(&ctor(NotExistsPredicate))
end

#make_not_in(expr) ⇒ Object



112
113
114
# File 'lib/google_data_source/sql/parser.rb', line 112

def make_not_in expr
  keyword[:not] >> keyword[:in] >> list(expr) >> map(&rctor(NotInPredicate))
end

#make_not_in_relation(rel) ⇒ Object



120
121
122
# File 'lib/google_data_source/sql/parser.rb', line 120

def make_not_in_relation rel
  keyword[:not] >> keyword[:in] >> rel.map(&rctor(NotInRelationPredicate))
end

#make_predicate(expr, rel) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/google_data_source/sql/parser.rb', line 84

def make_predicate expr, rel
  expr_list = list expr
  comparison = make_comparison_predicate expr, rel
  group_comparison = sequence(expr_list, Comparators, expr_list, &ctor(GroupComparisonPredicate))
  bool = nil
  lazy_bool = lazy{bool}
  bool_term = keyword[:true] >> true | keyword[:false] >> false |
    comparison | group_comparison | paren(lazy_bool) |
    make_exists(rel) | make_not_exists(rel)
  bool_table = OperatorTable.new.
    infixl(keyword[:or] >> logical_operator(:or), 20).
    infixl(keyword[:and] >> logical_operator(:and), 30).
    prefix(keyword[:not] >> ctor(NotPredicate), 40)
  bool = Expressions.build(bool_term, bool_table)
end

#make_relation(expr, pred) ⇒ Object

relation parser ###############################



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/google_data_source/sql/parser.rb', line 185

def make_relation expr, pred
  where_clause = keyword[:where] >> pred
  order_element = sequence(expr, (keyword[:asc] >> true | keyword[:desc] >> false).optional(true),
    &ctor(OrderElement))
  order_elements = order_element.separated1(comma)
  exprs = expr.separated1(comma)

  # setup clauses
  select_clause = keyword[:select] >> exprs
  order_by_clause = keyword[:order] >> keyword[:by] >> order_elements
  group_by = keyword[:group] >> keyword[:by] >> exprs
  group_by_clause = sequence(group_by, (keyword[:having] >> pred).optional, &ctor(GroupByClause))
  limit_clause = keyword[:limit] >> token(:number, &To_i)
  offset_clause = keyword[:offset] >> token(:number, &To_i)

  # build relation
  relation = sequence(
    select_clause.optional([WildcardExpr.new]),
    where_clause.optional, group_by_clause.optional, order_by_clause.optional,
    limit_clause.optional, offset_clause.optional
  ) do |select, where, groupby, orderby, limit, offset|
    SelectRelation.new(select, where, groupby, orderby, limit, offset)
  end
end

#operatorObject



47
48
49
# File 'lib/google_data_source/sql/parser.rb', line 47

def operator
  MyOperators
end

#paren(parser) ⇒ Object



67
68
69
# File 'lib/google_data_source/sql/parser.rb', line 67

def paren parser
  operator['('] >> parser << operator[')']
end

#predicateObject



218
219
220
# File 'lib/google_data_source/sql/parser.rb', line 218

def predicate
  assemble[1]
end

#rctor(cls, arity = 2) ⇒ Object



75
76
77
# File 'lib/google_data_source/sql/parser.rb', line 75

def rctor cls, arity=2
  ctor(cls).reverse_curry arity
end

#relationObject



215
216
217
# File 'lib/google_data_source/sql/parser.rb', line 215

def relation
  assemble[2]
end

#word(&block) ⇒ Object



59
60
61
62
63
64
65
# File 'lib/google_data_source/sql/parser.rb', line 59

def word(&block)
  if block.nil?
    token(:word, &Id)
  else
    token(:word, &block)
  end
end