ronin-code-sql 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.document +4 -0
  3. data/.editorconfig +11 -0
  4. data/.github/workflows/ruby.yml +27 -0
  5. data/.gitignore +11 -0
  6. data/.mailmap +1 -0
  7. data/.rspec +1 -0
  8. data/.ruby-version +1 -0
  9. data/.yardopts +1 -0
  10. data/COPYING.txt +165 -0
  11. data/ChangeLog.md +104 -0
  12. data/Gemfile +28 -0
  13. data/README.md +212 -0
  14. data/Rakefile +30 -0
  15. data/gemspec.yml +25 -0
  16. data/lib/ronin/code/sql/binary_expr.rb +53 -0
  17. data/lib/ronin/code/sql/clause.rb +74 -0
  18. data/lib/ronin/code/sql/clauses.rb +310 -0
  19. data/lib/ronin/code/sql/emittable.rb +88 -0
  20. data/lib/ronin/code/sql/emitter.rb +406 -0
  21. data/lib/ronin/code/sql/field.rb +110 -0
  22. data/lib/ronin/code/sql/fields.rb +82 -0
  23. data/lib/ronin/code/sql/function.rb +53 -0
  24. data/lib/ronin/code/sql/functions.rb +1265 -0
  25. data/lib/ronin/code/sql/injection.rb +168 -0
  26. data/lib/ronin/code/sql/injection_expr.rb +113 -0
  27. data/lib/ronin/code/sql/literal.rb +40 -0
  28. data/lib/ronin/code/sql/literals.rb +83 -0
  29. data/lib/ronin/code/sql/operators.rb +384 -0
  30. data/lib/ronin/code/sql/statement.rb +72 -0
  31. data/lib/ronin/code/sql/statement_list.rb +112 -0
  32. data/lib/ronin/code/sql/statements.rb +117 -0
  33. data/lib/ronin/code/sql/unary_expr.rb +38 -0
  34. data/lib/ronin/code/sql/version.rb +28 -0
  35. data/lib/ronin/code/sql.rb +96 -0
  36. data/ronin-code-sql.gemspec +62 -0
  37. data/spec/spec_helper.rb +3 -0
  38. data/spec/sql/binary_expr_examples.rb +25 -0
  39. data/spec/sql/binary_expr_spec.rb +5 -0
  40. data/spec/sql/clause_examples.rb +43 -0
  41. data/spec/sql/clause_spec.rb +31 -0
  42. data/spec/sql/clauses_spec.rb +47 -0
  43. data/spec/sql/emittable_spec.rb +41 -0
  44. data/spec/sql/emitter_spec.rb +533 -0
  45. data/spec/sql/field_spec.rb +103 -0
  46. data/spec/sql/fields_spec.rb +40 -0
  47. data/spec/sql/function_examples.rb +30 -0
  48. data/spec/sql/function_spec.rb +25 -0
  49. data/spec/sql/functions_spec.rb +113 -0
  50. data/spec/sql/injection_expr_spec.rb +98 -0
  51. data/spec/sql/injection_spec.rb +172 -0
  52. data/spec/sql/literal_spec.rb +5 -0
  53. data/spec/sql/literals_spec.rb +46 -0
  54. data/spec/sql/operators_spec.rb +44 -0
  55. data/spec/sql/statement_examples.rb +39 -0
  56. data/spec/sql/statement_list_spec.rb +48 -0
  57. data/spec/sql/statement_spec.rb +38 -0
  58. data/spec/sql/statements_spec.rb +22 -0
  59. data/spec/sql/unary_expr_examples.rb +20 -0
  60. data/spec/sql/unary_expr_spec.rb +5 -0
  61. data/spec/sql_spec.rb +18 -0
  62. metadata +157 -0
@@ -0,0 +1,384 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
+ #
5
+ # Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-code-sql is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-code-sql is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ module Ronin
22
+ module Code
23
+ module SQL
24
+ #
25
+ # Methods for creating SQL expressions.
26
+ #
27
+ # @api public
28
+ #
29
+ # @see http://sqlite.org/lang_expr.html
30
+ #
31
+ module Operators
32
+ #
33
+ # Multiplication.
34
+ #
35
+ # @param [Object] other
36
+ #
37
+ # @return [BinaryExpr]
38
+ # The new binary expression.
39
+ #
40
+ def *(other)
41
+ BinaryExpr.new(self,:*,other)
42
+ end
43
+
44
+ #
45
+ # Division.
46
+ #
47
+ # @param [Object] other
48
+ #
49
+ # @return [BinaryExpr]
50
+ # The new binary expression.
51
+ #
52
+ def /(other)
53
+ BinaryExpr.new(self,:/,other)
54
+ end
55
+
56
+ #
57
+ # Modulus.
58
+ #
59
+ # @param [Object] other
60
+ #
61
+ # @return [BinaryExpr]
62
+ # The new binary expression.
63
+ #
64
+ def %(other)
65
+ BinaryExpr.new(self,:%,other)
66
+ end
67
+
68
+ #
69
+ # Addition.
70
+ #
71
+ # @param [Object] other
72
+ #
73
+ # @return [BinaryExpr]
74
+ # The new binary expression.
75
+ #
76
+ def +(other)
77
+ BinaryExpr.new(self,:+,other)
78
+ end
79
+
80
+ #
81
+ # Subtraction.
82
+ #
83
+ # @param [Object] other
84
+ #
85
+ # @return [BinaryExpr]
86
+ # The new binary expression.
87
+ #
88
+ def -(other)
89
+ BinaryExpr.new(self,:-,other)
90
+ end
91
+
92
+ #
93
+ # Bit-wise left shift.
94
+ #
95
+ # @param [Object] other
96
+ #
97
+ # @return [BinaryExpr]
98
+ # The new binary expression.
99
+ #
100
+ def <<(other)
101
+ BinaryExpr.new(self,:<<,other)
102
+ end
103
+
104
+ #
105
+ # Bit-wise right shift.
106
+ #
107
+ # @param [Object] other
108
+ #
109
+ # @return [BinaryExpr]
110
+ # The new binary expression.
111
+ #
112
+ def >>(other)
113
+ BinaryExpr.new(self,:>>,other)
114
+ end
115
+
116
+ #
117
+ # Bit-wise `AND`.
118
+ #
119
+ # @param [Object] other
120
+ #
121
+ # @return [BinaryExpr]
122
+ # The new binary expression.
123
+ #
124
+ def &(other)
125
+ BinaryExpr.new(self,:&,other)
126
+ end
127
+
128
+ #
129
+ # Bit-wise `OR`.
130
+ #
131
+ # @param [Object] other
132
+ #
133
+ # @return [BinaryExpr]
134
+ # The new binary expression.
135
+ #
136
+ def |(other)
137
+ BinaryExpr.new(self,:|,other)
138
+ end
139
+
140
+ #
141
+ # Less than.
142
+ #
143
+ # @param [Object] other
144
+ #
145
+ # @return [BinaryExpr]
146
+ # The new binary expression.
147
+ #
148
+ def <(other)
149
+ BinaryExpr.new(self,:<,other)
150
+ end
151
+
152
+ #
153
+ # Less than or equal to.
154
+ #
155
+ # @param [Object] other
156
+ #
157
+ # @return [BinaryExpr]
158
+ # The new binary expression.
159
+ #
160
+ def <=(other)
161
+ BinaryExpr.new(self,:<=,other)
162
+ end
163
+
164
+ #
165
+ # Greater than.
166
+ #
167
+ # @param [Object] other
168
+ #
169
+ # @return [BinaryExpr]
170
+ # The new binary expression.
171
+ #
172
+ def >(other)
173
+ BinaryExpr.new(self,:>,other)
174
+ end
175
+
176
+ #
177
+ # Greater than or equal to.
178
+ #
179
+ # @param [Object] other
180
+ #
181
+ # @return [BinaryExpr]
182
+ # The new binary expression.
183
+ #
184
+ def >=(other)
185
+ BinaryExpr.new(self,:>=,other)
186
+ end
187
+
188
+ #
189
+ # Equal to.
190
+ #
191
+ # @param [Object] other
192
+ #
193
+ # @return [BinaryExpr]
194
+ # The new binary expression.
195
+ #
196
+ def ==(other)
197
+ BinaryExpr.new(self,:"=",other)
198
+ end
199
+
200
+ #
201
+ # Not equal to.
202
+ #
203
+ # @param [Object] other
204
+ #
205
+ # @return [BinaryExpr]
206
+ # The new binary expression.
207
+ #
208
+ def !=(other)
209
+ BinaryExpr.new(self,:!=,other)
210
+ end
211
+
212
+ #
213
+ # Alias.
214
+ #
215
+ # @param [Symbol] name
216
+ #
217
+ # @return [BinaryExpr]
218
+ # The new binary expression.
219
+ #
220
+ def as(name)
221
+ BinaryExpr.new(self,:AS,name)
222
+ end
223
+
224
+ #
225
+ # `IS` comparison.
226
+ #
227
+ # @param [Object] other
228
+ #
229
+ # @return [BinaryExpr]
230
+ # The new binary expression.
231
+ #
232
+ def is(other)
233
+ BinaryExpr.new(self,:IS,other)
234
+ end
235
+
236
+ #
237
+ # `IS NOT` comparison.
238
+ #
239
+ # @param [Object] other
240
+ #
241
+ # @return [BinaryExpr]
242
+ # The new binary expression.
243
+ #
244
+ def is_not(other)
245
+ BinaryExpr.new(self,[:IS, :NOT],other)
246
+ end
247
+
248
+ #
249
+ # `LIKE` comparison.
250
+ #
251
+ # @param [Object] other
252
+ #
253
+ # @return [BinaryExpr]
254
+ # The new binary expression.
255
+ #
256
+ def like(other)
257
+ BinaryExpr.new(self,:LIKE,other)
258
+ end
259
+
260
+ #
261
+ # `GLOB` comparison.
262
+ #
263
+ # @param [Object] other
264
+ #
265
+ # @return [BinaryExpr]
266
+ # The new binary expression.
267
+ #
268
+ def glob(other)
269
+ BinaryExpr.new(self,:GLOB,other)
270
+ end
271
+
272
+ #
273
+ # `MATCH` comparison.
274
+ #
275
+ # @param [Object] other
276
+ #
277
+ # @return [BinaryExpr]
278
+ # The new binary expression.
279
+ #
280
+ def match(other)
281
+ BinaryExpr.new(self,:MATCH,other)
282
+ end
283
+
284
+ #
285
+ # `REGEXP` comparison.
286
+ #
287
+ # @param [Object] other
288
+ #
289
+ # @return [BinaryExpr]
290
+ # The new binary expression.
291
+ #
292
+ def regexp(other)
293
+ BinaryExpr.new(self,:REGEXP,other)
294
+ end
295
+
296
+ #
297
+ # `REGEXP` comparison.
298
+ #
299
+ # @param [Object] other
300
+ #
301
+ # @return [BinaryExpr]
302
+ # The new binary expression.
303
+ #
304
+ def in(other)
305
+ BinaryExpr.new(self,:IN,other)
306
+ end
307
+
308
+ #
309
+ # Unary minus.
310
+ #
311
+ # @return [UnaryExpr]
312
+ # The new binary expression.
313
+ #
314
+ def -@
315
+ UnaryExpr.new(:-,self)
316
+ end
317
+
318
+ #
319
+ # Unary plus.
320
+ #
321
+ # @return [UnaryExpr]
322
+ # The new binary expression.
323
+ #
324
+ def +@
325
+ UnaryExpr.new(:+,self)
326
+ end
327
+
328
+ #
329
+ # Bit-wise negate.
330
+ #
331
+ # @return [UnaryExpr]
332
+ # The new binary expression.
333
+ #
334
+ def ~
335
+ UnaryExpr.new(:~,self)
336
+ end
337
+
338
+ #
339
+ # Logical negate.
340
+ #
341
+ # @return [UnaryExpr]
342
+ # The new binary expression.
343
+ #
344
+ def !
345
+ UnaryExpr.new(:!,self)
346
+ end
347
+
348
+ #
349
+ # Logical `NOT`.
350
+ #
351
+ # @return [UnaryExpr]
352
+ # The new binary expression.
353
+ #
354
+ def not
355
+ UnaryExpr.new(:NOT,self)
356
+ end
357
+
358
+ #
359
+ # `AND`.
360
+ #
361
+ # @param [Object] other
362
+ #
363
+ # @return [BinaryExpr]
364
+ # The new binary expression.
365
+ #
366
+ def and(other)
367
+ BinaryExpr.new(self,:AND,other)
368
+ end
369
+
370
+ #
371
+ # `OR`.
372
+ #
373
+ # @param [Object] other
374
+ #
375
+ # @return [BinaryExpr]
376
+ # The new binary expression.
377
+ #
378
+ def or(other)
379
+ BinaryExpr.new(self,:OR,other)
380
+ end
381
+ end
382
+ end
383
+ end
384
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
+ #
5
+ # Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-code-sql is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-code-sql is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/code/sql/literals'
22
+ require 'ronin/code/sql/clause'
23
+ require 'ronin/code/sql/clauses'
24
+ require 'ronin/code/sql/operators'
25
+ require 'ronin/code/sql/emittable'
26
+
27
+ module Ronin
28
+ module Code
29
+ module SQL
30
+ #
31
+ # Represents a SQL Statement.
32
+ #
33
+ # @api semipublic
34
+ #
35
+ class Statement < Struct.new(:keyword,:argument)
36
+
37
+ include Literals
38
+ include Operators
39
+ include Clauses
40
+ include Emittable
41
+
42
+ #
43
+ # Initializes a new SQL statement.
44
+ #
45
+ # @param [Symbol, Array<Symbol>] keyword
46
+ # Name of the statement.
47
+ #
48
+ # @param [Object] argument
49
+ # Additional argument for the statement.
50
+ #
51
+ # @yield [(statement)]
52
+ # If a block is given, it will be called.
53
+ #
54
+ # @yieldparam [Statement] statement
55
+ # If the block accepts an argument, it will be passed the new statement.
56
+ # Otherwise the block will be evaluated within the statement.
57
+ #
58
+ def initialize(keyword,argument=nil,&block)
59
+ super(keyword,argument)
60
+
61
+ if block
62
+ case block.arity
63
+ when 0 then instance_eval(&block)
64
+ else block.call(self)
65
+ end
66
+ end
67
+ end
68
+
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
+ #
5
+ # Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-code-sql is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-code-sql is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/code/sql/field'
22
+ require 'ronin/code/sql/fields'
23
+ require 'ronin/code/sql/unary_expr'
24
+ require 'ronin/code/sql/binary_expr'
25
+ require 'ronin/code/sql/functions'
26
+ require 'ronin/code/sql/statement'
27
+ require 'ronin/code/sql/statements'
28
+ require 'ronin/code/sql/emittable'
29
+
30
+ module Ronin
31
+ module Code
32
+ module SQL
33
+ #
34
+ # Represents a list of SQL {Statements Statement}.
35
+ #
36
+ # @api public
37
+ #
38
+ class StatementList
39
+
40
+ include Fields
41
+ include Functions
42
+ include Statements
43
+ include Emittable
44
+
45
+ # The list of statements
46
+ attr_reader :statements
47
+
48
+ #
49
+ # Initializes a new SQL statement list.
50
+ #
51
+ # @yield [(statements)]
52
+ # If a block is given, it will be evaluated within the statement list.
53
+ # If the block accepts an argument, the block will be called with the
54
+ # new statement list.
55
+ #
56
+ # @yieldparam [StatementList] statements
57
+ # The new statement list.
58
+ #
59
+ def initialize(&block)
60
+ @statements = []
61
+
62
+ if block
63
+ case block.arity
64
+ when 0 then instance_eval(&block)
65
+ else block.call(self)
66
+ end
67
+ end
68
+ end
69
+
70
+ #
71
+ # Appends a statement.
72
+ #
73
+ # @param [Statement] statement
74
+ # The SQL statement.
75
+ #
76
+ # @return [self]
77
+ #
78
+ def <<(statement)
79
+ @statements << statement
80
+ return self
81
+ end
82
+
83
+ #
84
+ # Appends an arbitrary statement.
85
+ #
86
+ # @param [Symbol] keyword
87
+ # Name of the statement.
88
+ #
89
+ # @param [Object] argument
90
+ # Additional argument for the statement.
91
+ #
92
+ # @yield [(statement)]
93
+ # If a block is given, it will be called.
94
+ #
95
+ # @yieldparam [Statement] statement
96
+ # If the block accepts an argument, it will be passed the new statement.
97
+ # Otherwise the block will be evaluated within the statement.
98
+ #
99
+ # @return [Statement]
100
+ # The newly created statement.
101
+ #
102
+ def statement(keyword,argument=nil,&block)
103
+ new_statement = super
104
+
105
+ self << new_statement
106
+ return new_statement
107
+ end
108
+
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
+ #
5
+ # Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-code-sql is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-code-sql is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ module Ronin
22
+ module Code
23
+ module SQL
24
+ #
25
+ # Methods for creating common SQL {Statement Statements}.
26
+ #
27
+ # @api public
28
+ #
29
+ module Statements
30
+ #
31
+ # Creates an arbitrary statement.
32
+ #
33
+ # @param [Symbol] keyword
34
+ # Name of the statement.
35
+ #
36
+ # @param [Object] argument
37
+ # Additional argument for the statement.
38
+ #
39
+ # @yield [(statement)]
40
+ # If a block is given, it will be called.
41
+ #
42
+ # @yieldparam [Statement] statement
43
+ # If the block accepts an argument, it will be passed the new statement.
44
+ # Otherwise the block will be evaluated within the statement.
45
+ #
46
+ # @return [Statement]
47
+ # The new statement.
48
+ #
49
+ def statement(keyword,argument=nil,&block)
50
+ Statement.new(keyword,argument,&block)
51
+ end
52
+
53
+ #
54
+ # Creates a new `SELECT` statement.
55
+ #
56
+ # @param [Array<Field, Symbol>] columns
57
+ # The columns to select.
58
+ #
59
+ # @return [Statement]
60
+ # The new statement.
61
+ #
62
+ def select(*columns,&block)
63
+ statement(:SELECT,columns,&block)
64
+ end
65
+
66
+ #
67
+ # Creates a new `INSERT` statement.
68
+ #
69
+ # @return [Statement]
70
+ # The new statement.
71
+ #
72
+ def insert(&block)
73
+ statement(:INSERT,&block)
74
+ end
75
+
76
+ #
77
+ # Creates a new `UPDATE` statement.
78
+ #
79
+ # @param [Field, Symbol] table
80
+ # The table to update.
81
+ #
82
+ # @return [Statement]
83
+ # The new statement.
84
+ #
85
+ def update(table,&block)
86
+ statement(:UPDATE,table,&block)
87
+ end
88
+
89
+ #
90
+ # Creates a new `DELETE` statement.
91
+ #
92
+ # @param [Field, Symbol] table
93
+ # The table to delete from.
94
+ #
95
+ # @return [Statement]
96
+ # The new statement.
97
+ #
98
+ def delete(table,&block)
99
+ statement([:DELETE, :FROM],table,&block)
100
+ end
101
+
102
+ #
103
+ # Creates a new `DROP TABLE` statement.
104
+ #
105
+ # @param [Field, Symbol] table
106
+ # The table to drop.
107
+ #
108
+ # @return [Statement]
109
+ # The new statement.
110
+ #
111
+ def drop_table(table,&block)
112
+ statement([:DROP, :TABLE],table,&block)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+ #
3
+ # ronin-code-sql - A Ruby DSL for crafting SQL Injections.
4
+ #
5
+ # Copyright (c) 2007-2022 Hal Brodigan (postmodern.mod3 at gmail.com)
6
+ #
7
+ # ronin-code-sql is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published
9
+ # by the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # ronin-code-sql is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with ronin-code-sql. If not, see <https://www.gnu.org/licenses/>.
19
+ #
20
+
21
+ require 'ronin/code/sql/emittable'
22
+
23
+ module Ronin
24
+ module Code
25
+ module SQL
26
+ #
27
+ # Represents a unary expression in SQL.
28
+ #
29
+ # @api semipublic
30
+ #
31
+ class UnaryExpr < Struct.new(:operator,:operand)
32
+
33
+ include Emittable
34
+
35
+ end
36
+ end
37
+ end
38
+ end