sql-parser-tl 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,383 @@
1
+ module SQLParser
2
+
3
+ class SQLVisitor
4
+
5
+ def initialize
6
+ @negated = false
7
+ end
8
+
9
+ def visit(node)
10
+ node.accept(self)
11
+ end
12
+
13
+ def visit_Insert(o)
14
+ name = visit(o.table_reference)
15
+ columns = ' ' + visit(o.column_list) if o.column_list
16
+ values = ' VALUES ' + visit(o.in_value_list)
17
+ "INSERT INTO #{name}#{columns}#{values}"
18
+ end
19
+
20
+ def visit_DirectSelect(o)
21
+ [
22
+ o.query_expression,
23
+ o.order_by,
24
+ o.limit_clause
25
+ ].compact.collect { |e| visit(e) }.join(' ')
26
+ end
27
+
28
+ def visit_OrderBy(o)
29
+ "ORDER BY #{arrayize(o.sort_specification)}"
30
+ end
31
+
32
+ def visit_LimitClause(o)
33
+ "LIMIT #{o.limit} OFFSET #{o.offset}"
34
+ end
35
+
36
+ def visit_Subquery(o)
37
+ "(#{visit(o.query_specification)})"
38
+ end
39
+
40
+ def visit_Select(o)
41
+ # FIXME: This feels like a hack
42
+ initialize
43
+
44
+ "SELECT #{visit_all([o.list, o.table_expression].compact).join(' ')}"
45
+ end
46
+
47
+ def visit_SelectList(o)
48
+ arrayize(o.columns)
49
+ end
50
+
51
+ def visit_Distinct(o)
52
+ "DISTINCT(#{visit(o.column)})"
53
+ end
54
+
55
+ def visit_All(o)
56
+ '*'
57
+ end
58
+
59
+ def visit_TableExpression(o)
60
+ [
61
+ o.from_clause,
62
+ o.where_clause,
63
+ o.group_by_clause,
64
+ o.having_clause
65
+ ].compact.collect { |e| visit(e) }.join(' ')
66
+ end
67
+
68
+ def visit_FromClause(o)
69
+ "FROM #{arrayize(o.tables)}"
70
+ end
71
+
72
+ def visit_OrderClause(o)
73
+ "ORDER BY #{arrayize(o.columns)}"
74
+ end
75
+
76
+ def visit_Ascending(o)
77
+ "#{visit(o.column)} ASC"
78
+ end
79
+
80
+ def visit_Descending(o)
81
+ "#{visit(o.column)} DESC"
82
+ end
83
+
84
+ def visit_HavingClause(o)
85
+ "HAVING #{visit(o.search_condition)}"
86
+ end
87
+
88
+ def visit_GroupByClause(o)
89
+ "GROUP BY #{arrayize(o.columns)}"
90
+ end
91
+
92
+ def visit_WhereClause(o)
93
+ "WHERE #{visit(o.search_condition)}"
94
+ end
95
+
96
+ def visit_On(o)
97
+ "ON #{visit(o.search_condition)}"
98
+ end
99
+
100
+ def visit_Using(o)
101
+ "USING (#{arrayize(o.columns)})"
102
+ end
103
+
104
+ def visit_Or(o)
105
+ search_condition('OR', o)
106
+ end
107
+
108
+ def visit_And(o)
109
+ search_condition('AND', o)
110
+ end
111
+
112
+ def visit_Exists(o)
113
+ if @negated
114
+ "NOT EXISTS #{visit(o.table_subquery)}"
115
+ else
116
+ "EXISTS #{visit(o.table_subquery)}"
117
+ end
118
+ end
119
+
120
+ def visit_Is(o)
121
+ if @negated
122
+ comparison('IS NOT', o)
123
+ else
124
+ comparison('IS', o)
125
+ end
126
+ end
127
+
128
+ def visit_Like(o)
129
+ if @negated
130
+ comparison('NOT LIKE', o)
131
+ else
132
+ comparison('LIKE', o)
133
+ end
134
+ end
135
+
136
+ def visit_In(o)
137
+ if @negated
138
+ comparison('NOT IN', o)
139
+ else
140
+ comparison('IN', o)
141
+ end
142
+ end
143
+
144
+ def visit_InColumnList(o)
145
+ "(#{arrayize(o.columns)})"
146
+ end
147
+
148
+ def visit_InValueList(o)
149
+ "(#{arrayize(o.values)})"
150
+ end
151
+
152
+ def visit_Between(o)
153
+ if @negated
154
+ comparison('NOT BETWEEN', o)
155
+ else
156
+ comparison('BETWEEN', o)
157
+ end
158
+ end
159
+
160
+ def visit_BetweenRange(o)
161
+ "#{visit(o.min)} AND #{visit(o.max)}"
162
+ end
163
+
164
+ def visit_GreaterOrEquals(o)
165
+ comparison('>=', o)
166
+ end
167
+
168
+ def visit_LessOrEquals(o)
169
+ comparison('<=', o)
170
+ end
171
+
172
+ def visit_Greater(o)
173
+ comparison('>', o)
174
+ end
175
+
176
+ def visit_Less(o)
177
+ comparison('<', o)
178
+ end
179
+
180
+ def visit_Equals(o)
181
+ if @negated
182
+ comparison('<>', o)
183
+ else
184
+ comparison('=', o)
185
+ end
186
+ end
187
+
188
+ def visit_Sum(o)
189
+ aggregate('SUM', o)
190
+ end
191
+
192
+ def visit_Minimum(o)
193
+ aggregate('MIN', o)
194
+ end
195
+
196
+ def visit_Maximum(o)
197
+ aggregate('MAX', o)
198
+ end
199
+
200
+ def visit_Average(o)
201
+ aggregate('AVG', o)
202
+ end
203
+
204
+ def visit_Count(o)
205
+ aggregate('COUNT', o)
206
+ end
207
+
208
+ def visit_CrossJoin(o)
209
+ "#{visit(o.left)} CROSS JOIN #{visit(o.right)}"
210
+ end
211
+
212
+ def visit_InnerJoin(o)
213
+ qualified_join('INNER', o)
214
+ end
215
+
216
+ def visit_LeftJoin(o)
217
+ qualified_join('LEFT', o)
218
+ end
219
+
220
+ def visit_LeftOuterJoin(o)
221
+ qualified_join('LEFT OUTER', o)
222
+ end
223
+
224
+ def visit_RightJoin(o)
225
+ qualified_join('RIGHT', o)
226
+ end
227
+
228
+ def visit_RightOuterJoin(o)
229
+ qualified_join('RIGHT OUTER', o)
230
+ end
231
+
232
+ def visit_FullJoin(o)
233
+ qualified_join('FULL', o)
234
+ end
235
+
236
+ def visit_FullOuterJoin(o)
237
+ qualified_join('FULL OUTER', o)
238
+ end
239
+
240
+ def visit_Table(o)
241
+ quote(o.name)
242
+ end
243
+
244
+ def visit_QualifiedColumn(o)
245
+ "#{visit(o.table)}.#{visit(o.column)}"
246
+ end
247
+
248
+ def visit_Column(o)
249
+ quote(o.name)
250
+ end
251
+
252
+ def visit_As(o)
253
+ "#{visit(o.original)} AS #{visit(o.alias)}"
254
+ end
255
+
256
+ def visit_ForceIndex(o)
257
+ "#{visit(o.table)} FORCE INDEX (`#{o.index}`)"
258
+ end
259
+
260
+ def visit_UseIndex(o)
261
+ "#{visit(o.table)} USE INDEX (`#{o.index}`)"
262
+ end
263
+
264
+ def visit_IgnoreIndex(o)
265
+ "#{visit(o.table)} IGNORE INDEX (`#{o.index}`)"
266
+ end
267
+
268
+ def visit_Multiply(o)
269
+ arithmetic('*', o)
270
+ end
271
+
272
+ def visit_Divide(o)
273
+ arithmetic('/', o)
274
+ end
275
+
276
+ def visit_Add(o)
277
+ arithmetic('+', o)
278
+ end
279
+
280
+ def visit_Subtract(o)
281
+ arithmetic('-', o)
282
+ end
283
+
284
+ def visit_Not(o)
285
+ negate { visit(o.value) }
286
+ end
287
+
288
+ def visit_UnaryPlus(o)
289
+ "+#{visit(o.value)}"
290
+ end
291
+
292
+ def visit_UnaryMinus(o)
293
+ "-#{visit(o.value)}"
294
+ end
295
+
296
+ def visit_True(o)
297
+ 'TRUE'
298
+ end
299
+
300
+ def visit_False(o)
301
+ 'FALSE'
302
+ end
303
+
304
+ def visit_Null(o)
305
+ 'NULL'
306
+ end
307
+
308
+ def visit_CurrentUser(o)
309
+ 'CURRENT_USER'
310
+ end
311
+
312
+ def visit_DateTime(o)
313
+ "'%s'" % escape(o.value.strftime('%Y-%m-%d %H:%M:%S'))
314
+ end
315
+
316
+ def visit_Date(o)
317
+ "DATE '%s'" % escape(o.value.strftime('%Y-%m-%d'))
318
+ end
319
+
320
+ def visit_String(o)
321
+ "'%s'" % escape(o.value)
322
+ end
323
+
324
+ def visit_ApproximateFloat(o)
325
+ "#{visit(o.mantissa)}E#{visit(o.exponent)}"
326
+ end
327
+
328
+ def visit_Float(o)
329
+ o.value.to_s
330
+ end
331
+
332
+ def visit_Integer(o)
333
+ o.value.to_s
334
+ end
335
+
336
+ private
337
+
338
+ def negate
339
+ @negated = true
340
+ yield
341
+ ensure
342
+ @negated = false
343
+ end
344
+
345
+ def quote(str)
346
+ "`#{str}`"
347
+ end
348
+
349
+ def escape(str)
350
+ str.gsub(/'/, "''")
351
+ end
352
+
353
+ def arithmetic(operator, o)
354
+ search_condition(operator, o)
355
+ end
356
+
357
+ def comparison(operator, o)
358
+ [visit(o.left), operator, visit(o.right)].join(' ')
359
+ end
360
+
361
+ def search_condition(operator, o)
362
+ "(#{visit(o.left)} #{operator} #{visit(o.right)})"
363
+ end
364
+
365
+ def visit_all(nodes)
366
+ nodes.collect { |e| visit(e) }
367
+ end
368
+
369
+ def arrayize(arr)
370
+ visit_all(arr).join(', ')
371
+ end
372
+
373
+ def aggregate(function_name, o)
374
+ "#{function_name}(#{visit(o.column)})"
375
+ end
376
+
377
+ def qualified_join(join_type, o)
378
+ "#{visit(o.left)} #{join_type} JOIN #{visit(o.right)} #{visit(o.search_condition)}"
379
+ end
380
+
381
+ end
382
+
383
+ end