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