sql_search_parser 0.0.2

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 66866005a717ecfd956c7e12def19dd1bf84d1ce
4
+ data.tar.gz: 6a234f90d1ffd9ebe1a3fadb405327116f69dd90
5
+ SHA512:
6
+ metadata.gz: d1e18ffd9a85b75be8d76d26e1f191c5d7eef31f9de446987b586d01b9333718b22149f5f44693961a4ad0bfa06a4212643a6b9c6894771e7b6b4b44f3a87727
7
+ data.tar.gz: 56de07980807906da360b056fb6784e9ef4e76368f1b2a45952e4084794def05926b27ee92ab31ee504d550210a87ee6eb4f85510b0841b2a06423136fbf7078
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 NIEK Antoine
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,50 @@
1
+ sql_search_parser
2
+ =================
3
+
4
+ Simple SQL search conditions parser (where clause) based on RACC
5
+
6
+ Usage
7
+ -----
8
+ SQLSearch::Parser.new.parse("a = 2")
9
+ => #<SQLSearch::Comparison:0x00000000fd12e0 @left=#<SQLSearch::Atoms::Column:0x00000000fd1588 @name="a", @table=nil, @space=nil>, @right=#<SQLSearch::Atoms::Literal:0x00000000fd1380 @value=2, @type=:int>, @operator=:"=">
10
+
11
+ SQLSearch::Parser.new.parse("a = 2 and b = 3").to_s
12
+ => "(`a` = 2) AND (`b` = 3)"
13
+
14
+ SQLSearch::Parser.new.parse("b = '2013-01-01T00:00:00Z'").right.value
15
+ => #<DateTime: 2013-01-01T00:00:00+00:00 ((2456294j,0s,0n),+0s,2299161j)>
16
+
17
+ SQLSearch::Parser.new.parse("b = '2013-01-01T00:00:00-05:00'").right.value
18
+ => #<DateTime: 2013-01-01T00:00:00-05:00 ((2456294j,18000s,0n),-18000s,2299161j)>
19
+
20
+ SQLSearch::Parser.new.parse("b IN(1,2,3)").right.values.map(&:value)
21
+ => [1, 2, 3]
22
+
23
+ SQLSearch::Parser.new.parse("b + 1 > c").left
24
+ => #<SQLSearch::Atoms::Scalar:0x000000016ceef8 @left=#<SQLSearch::Atoms::Column:0x000000016cf308 @name="b", @table=nil, @space=nil>, @right=#<SQLSearch::Atoms::Literal:0x000000016cf100 @value=1, @type=:int>, @operation=:+>
25
+
26
+ For more examples look at the tests :)
27
+
28
+ Installation
29
+ ------------
30
+ gem install sql_search_parser
31
+
32
+ or add in your Gemfile
33
+
34
+ gem 'sql_search_parser'
35
+
36
+ Build Dependencies
37
+ ------------------
38
+ rake, rexical, racc
39
+
40
+ Build & install Gem locally
41
+ -----
42
+ rake package
43
+
44
+ Run the tests
45
+ -----
46
+ rake
47
+
48
+ or
49
+
50
+ rake test
data/Rakefile ADDED
@@ -0,0 +1,26 @@
1
+ require_relative 'lib/sql_search/version'
2
+ require 'rake/testtask'
3
+
4
+ desc "Generate Lexer"
5
+
6
+ task :lexer do
7
+ `rex lib/sql_search/parser.rex -o lib/sql_search/parser.rex.rb`
8
+ end
9
+
10
+ task :parser do
11
+ `racc lib/sql_search/parser.y -o lib/sql_search/parser.racc.rb`
12
+ end
13
+
14
+ task :build => [:lexer, :parser]
15
+
16
+ task :package => [:build] do
17
+ `gem build sql_search_parser.gemspec`
18
+ `gem install sql_search_parser-#{SQLSearch::VERSION}.gem`
19
+ end
20
+
21
+ Rake::TestTask.new do |t|
22
+ t.pattern = "test/**/*_test.rb"
23
+ end
24
+
25
+ task :default => [:test]
26
+
@@ -0,0 +1,485 @@
1
+ #
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by Racc 1.4.11
4
+ # from Racc grammer file "".
5
+ #
6
+
7
+ require 'racc/parser.rb'
8
+
9
+ require 'date'
10
+ require_relative 'parser.rex.rb'
11
+
12
+ module SQLSearch
13
+ class Parser < Racc::Parser
14
+
15
+ module_eval(<<'...end parser.y/module_eval...', 'parser.y', 94)
16
+ def parse(input)
17
+ scan_str(input)
18
+ end
19
+ ...end parser.y/module_eval...
20
+ ##### State transition tables begin ###
21
+
22
+ racc_action_table = [
23
+ 2, 3, 48, 49, 53, 58, 77, 50, 64, 2,
24
+ 3, 12, 13, 59, 78, 16, 17, 18, 19, 20,
25
+ 12, 13, 2, 3, 16, 17, 18, 19, 20, 22,
26
+ 23, 2, 3, 12, 13, 22, 23, 16, 17, 18,
27
+ 19, 20, 12, 13, 2, 3, 16, 17, 18, 19,
28
+ 20, 22, 23, 70, 39, 12, 13, 67, 67, 16,
29
+ 17, 18, 19, 20, 12, 13, 39, 79, 16, 17,
30
+ 18, 19, 20, 71, 42, 39, 12, 13, 41, 36,
31
+ 16, 17, 18, 19, 20, 12, 13, 39, 61, 16,
32
+ 17, 18, 19, 20, nil, nil, 39, 12, 13, nil,
33
+ nil, 16, 17, 18, 19, 20, 12, 13, 39, nil,
34
+ 16, 17, 18, 19, 20, nil, nil, 39, 12, 13,
35
+ nil, nil, 16, 17, 18, 19, 20, 12, 13, 39,
36
+ nil, 16, 17, 18, 19, 20, nil, nil, 39, 12,
37
+ 13, nil, nil, 16, 17, 18, 19, 20, 12, 13,
38
+ 39, nil, 16, 17, 18, 19, 20, nil, nil, 39,
39
+ 12, 13, nil, nil, 16, 17, 18, 19, 20, 12,
40
+ 13, 39, 81, 16, 17, 18, 19, 20, 65, nil,
41
+ 78, 12, 13, 72, nil, 16, 17, 18, 19, 20,
42
+ 32, 33, 34, 35, nil, 32, 33, 34, 35, 28,
43
+ nil, nil, 27, 29, 30, 22, 23, nil, 31, 45,
44
+ 32, 33, 34, 35, 28, nil, 46, 27, 29, 30,
45
+ 46, nil, nil, 31, nil, 32, 33, 34, 35, 32,
46
+ 33, 34, 35, 16, 17, 18, 19, 16, 17, 18,
47
+ 19, 32, 33, 34, 35, 32, 33, 34, 35, 32,
48
+ 33, 34, 35, 21, nil, 22, 23, 16, 17, 18,
49
+ 19, 16, 17, 18, 19, 32, 33, 34, 35, 16,
50
+ 17, 18, 19, 16, 17, 18, 19, 32, 33, 34,
51
+ 35, 32, 33, 34, 35, 32, 33, 34, 35, 32,
52
+ 33, 34, 35, 32, 33, 34, 35 ]
53
+
54
+ racc_action_check = [
55
+ 0, 0, 28, 28, 31, 36, 68, 28, 50, 23,
56
+ 23, 0, 0, 36, 68, 0, 0, 0, 0, 0,
57
+ 23, 23, 2, 2, 23, 23, 23, 23, 23, 44,
58
+ 44, 3, 3, 2, 2, 24, 24, 2, 2, 2,
59
+ 2, 2, 3, 3, 22, 22, 3, 3, 3, 3,
60
+ 3, 43, 43, 58, 35, 22, 22, 52, 63, 22,
61
+ 22, 22, 22, 22, 35, 35, 12, 71, 35, 35,
62
+ 35, 35, 35, 61, 21, 13, 12, 12, 20, 11,
63
+ 12, 12, 12, 12, 12, 13, 13, 39, 41, 13,
64
+ 13, 13, 13, 13, nil, nil, 34, 39, 39, nil,
65
+ nil, 39, 39, 39, 39, 39, 34, 34, 65, nil,
66
+ 34, 34, 34, 34, 34, nil, nil, 48, 65, 65,
67
+ nil, nil, 65, 65, 65, 65, 65, 48, 48, 72,
68
+ nil, 48, 48, 48, 48, 48, nil, nil, 29, 72,
69
+ 72, nil, nil, 72, 72, 72, 72, 72, 29, 29,
70
+ 32, nil, 29, 29, 29, 29, 29, nil, nil, 27,
71
+ 32, 32, nil, nil, 32, 32, 32, 32, 32, 27,
72
+ 27, 33, 74, 27, 27, 27, 27, 27, 51, nil,
73
+ 74, 33, 33, 62, nil, 33, 33, 33, 33, 33,
74
+ 51, 51, 51, 51, nil, 62, 62, 62, 62, 10,
75
+ nil, nil, 10, 10, 10, 25, 25, nil, 10, 25,
76
+ 10, 10, 10, 10, 26, nil, 26, 26, 26, 26,
77
+ 60, nil, nil, 26, nil, 26, 26, 26, 26, 60,
78
+ 60, 60, 60, 67, 67, 67, 67, 78, 78, 78,
79
+ 78, 40, 40, 40, 40, 37, 37, 37, 37, 47,
80
+ 47, 47, 47, 1, nil, 1, 1, 49, 49, 49,
81
+ 49, 64, 64, 64, 64, 75, 75, 75, 75, 30,
82
+ 30, 30, 30, 53, 53, 53, 53, 54, 54, 54,
83
+ 54, 55, 55, 55, 55, 56, 56, 56, 56, 57,
84
+ 57, 57, 57, 80, 80, 80, 80 ]
85
+
86
+ racc_action_pointer = [
87
+ -4, 253, 18, 27, nil, nil, nil, nil, nil, nil,
88
+ 195, 68, 61, 70, nil, nil, nil, nil, nil, nil,
89
+ 54, 74, 40, 5, 33, 203, 210, 154, -6, 133,
90
+ 250, -1, 145, 166, 91, 49, 1, 230, nil, 82,
91
+ 226, 65, nil, 49, 27, nil, nil, 234, 112, 238,
92
+ 3, 175, 47, 254, 262, 266, 270, 274, 41, nil,
93
+ 214, 49, 180, 48, 242, 103, nil, 214, 0, nil,
94
+ nil, 44, 124, nil, 166, 250, nil, nil, 218, nil,
95
+ 278, nil, nil ]
96
+
97
+ racc_action_default = [
98
+ -41, -41, -41, -41, -5, -6, -7, -8, -9, -10,
99
+ -41, -31, -41, -41, -30, -33, -34, -35, -36, -37,
100
+ -38, -41, -41, -41, -3, -41, -41, -41, -41, -41,
101
+ -41, -41, -41, -41, -41, -41, -41, -28, -31, -41,
102
+ -29, -41, 83, -1, -2, -4, -32, -11, -41, -41,
103
+ -41, -41, -16, -41, -24, -25, -26, -27, -41, -19,
104
+ -41, -39, -41, -16, -41, -41, -15, -41, -41, -22,
105
+ -18, -41, -41, -14, -41, -13, -17, -21, -41, -40,
106
+ -12, -20, -23 ]
107
+
108
+ racc_goto_table = [
109
+ 26, 66, nil, nil, 52, 68, nil, nil, nil, 37,
110
+ 40, 1, 73, 24, 25, nil, 74, 11, nil, 11,
111
+ 11, nil, nil, 63, 47, nil, 51, 69, nil, 54,
112
+ 55, 56, 57, 43, 44, nil, 60, nil, 69, 11,
113
+ 11, 76, nil, nil, nil, 62, nil, nil, nil, nil,
114
+ nil, nil, 82, nil, nil, nil, nil, nil, nil, nil,
115
+ nil, nil, 75, nil, nil, nil, nil, nil, nil, 80 ]
116
+
117
+ racc_goto_check = [
118
+ 8, 10, nil, nil, 9, 12, nil, nil, nil, 8,
119
+ 8, 1, 10, 1, 1, nil, 12, 11, nil, 11,
120
+ 11, nil, nil, 9, 8, nil, 8, 9, nil, 8,
121
+ 8, 8, 8, 1, 1, nil, 8, nil, 9, 11,
122
+ 11, 9, nil, nil, nil, 8, nil, nil, nil, nil,
123
+ nil, nil, 9, nil, nil, nil, nil, nil, nil, nil,
124
+ nil, nil, 8, nil, nil, nil, nil, nil, nil, 8 ]
125
+
126
+ racc_goto_pointer = [
127
+ nil, 11, nil, nil, nil, nil, nil, nil, -3, -26,
128
+ -51, 17, -48, nil ]
129
+
130
+ racc_goto_default = [
131
+ nil, nil, 4, 5, 6, 7, 8, 9, 10, 14,
132
+ nil, 38, nil, 15 ]
133
+
134
+ racc_reduce_table = [
135
+ 0, 0, :racc_error,
136
+ 3, 26, :_reduce_1,
137
+ 3, 26, :_reduce_2,
138
+ 2, 26, :_reduce_3,
139
+ 3, 26, :_reduce_none,
140
+ 1, 26, :_reduce_none,
141
+ 1, 27, :_reduce_none,
142
+ 1, 27, :_reduce_none,
143
+ 1, 27, :_reduce_none,
144
+ 1, 27, :_reduce_none,
145
+ 1, 27, :_reduce_none,
146
+ 3, 28, :_reduce_11,
147
+ 6, 29, :_reduce_none,
148
+ 5, 29, :_reduce_none,
149
+ 5, 30, :_reduce_14,
150
+ 4, 30, :_reduce_15,
151
+ 0, 35, :_reduce_none,
152
+ 2, 35, :_reduce_none,
153
+ 4, 31, :_reduce_18,
154
+ 3, 31, :_reduce_19,
155
+ 6, 32, :_reduce_20,
156
+ 5, 32, :_reduce_21,
157
+ 1, 37, :_reduce_22,
158
+ 3, 37, :_reduce_23,
159
+ 3, 33, :_reduce_24,
160
+ 3, 33, :_reduce_25,
161
+ 3, 33, :_reduce_26,
162
+ 3, 33, :_reduce_27,
163
+ 2, 33, :_reduce_28,
164
+ 2, 33, :_reduce_29,
165
+ 1, 33, :_reduce_none,
166
+ 1, 33, :_reduce_none,
167
+ 3, 33, :_reduce_none,
168
+ 1, 34, :_reduce_none,
169
+ 1, 38, :_reduce_34,
170
+ 1, 38, :_reduce_35,
171
+ 1, 38, :_reduce_36,
172
+ 1, 38, :_reduce_37,
173
+ 1, 36, :_reduce_38,
174
+ 3, 36, :_reduce_39,
175
+ 5, 36, :_reduce_40 ]
176
+
177
+ racc_reduce_n = 41
178
+
179
+ racc_shift_n = 83
180
+
181
+ racc_token_table = {
182
+ false => 0,
183
+ :error => 1,
184
+ :OR => 2,
185
+ :AND => 3,
186
+ :NOT => 4,
187
+ :LPAREN => 5,
188
+ :RPAREN => 6,
189
+ :COMPARISON => 7,
190
+ :BETWEEN => 8,
191
+ :LIKE => 9,
192
+ :ESCAPE => 10,
193
+ :IS => 11,
194
+ :NULL => 12,
195
+ :IN => 13,
196
+ :COMMA => 14,
197
+ :ADD => 15,
198
+ :SUBTRACT => 16,
199
+ :MULTIPLY => 17,
200
+ :DIVIDE => 18,
201
+ :STRING => 19,
202
+ :APPROXNUM => 20,
203
+ :INTNUM => 21,
204
+ :TIME => 22,
205
+ :NAME => 23,
206
+ :DOT => 24 }
207
+
208
+ racc_nt_base = 25
209
+
210
+ racc_use_result_var = true
211
+
212
+ Racc_arg = [
213
+ racc_action_table,
214
+ racc_action_check,
215
+ racc_action_default,
216
+ racc_action_pointer,
217
+ racc_goto_table,
218
+ racc_goto_check,
219
+ racc_goto_default,
220
+ racc_goto_pointer,
221
+ racc_nt_base,
222
+ racc_reduce_table,
223
+ racc_token_table,
224
+ racc_shift_n,
225
+ racc_reduce_n,
226
+ racc_use_result_var ]
227
+
228
+ Racc_token_to_s_table = [
229
+ "$end",
230
+ "error",
231
+ "OR",
232
+ "AND",
233
+ "NOT",
234
+ "LPAREN",
235
+ "RPAREN",
236
+ "COMPARISON",
237
+ "BETWEEN",
238
+ "LIKE",
239
+ "ESCAPE",
240
+ "IS",
241
+ "NULL",
242
+ "IN",
243
+ "COMMA",
244
+ "ADD",
245
+ "SUBTRACT",
246
+ "MULTIPLY",
247
+ "DIVIDE",
248
+ "STRING",
249
+ "APPROXNUM",
250
+ "INTNUM",
251
+ "TIME",
252
+ "NAME",
253
+ "DOT",
254
+ "$start",
255
+ "search_condition",
256
+ "predicate",
257
+ "comparison_predicate",
258
+ "between_predicate",
259
+ "like_predicate",
260
+ "test_for_null",
261
+ "in_predicate",
262
+ "scalar_exp",
263
+ "atom",
264
+ "opt_escape",
265
+ "column_ref",
266
+ "atom_commalist",
267
+ "literal" ]
268
+
269
+ Racc_debug_parser = false
270
+
271
+ ##### State transition tables end #####
272
+
273
+ # reduce 0 omitted
274
+
275
+ module_eval(<<'.,.,', 'parser.y', 6)
276
+ def _reduce_1(val, _values, result)
277
+ result = Conditions::Or.new(:left => val[0], :right => val[2])
278
+ result
279
+ end
280
+ .,.,
281
+
282
+ module_eval(<<'.,.,', 'parser.y', 7)
283
+ def _reduce_2(val, _values, result)
284
+ result = Conditions::And.new(:left => val[0], :right => val[2])
285
+ result
286
+ end
287
+ .,.,
288
+
289
+ module_eval(<<'.,.,', 'parser.y', 8)
290
+ def _reduce_3(val, _values, result)
291
+ result = Conditions::Not.new(:value => val[1])
292
+ result
293
+ end
294
+ .,.,
295
+
296
+ # reduce 4 omitted
297
+
298
+ # reduce 5 omitted
299
+
300
+ # reduce 6 omitted
301
+
302
+ # reduce 7 omitted
303
+
304
+ # reduce 8 omitted
305
+
306
+ # reduce 9 omitted
307
+
308
+ # reduce 10 omitted
309
+
310
+ module_eval(<<'.,.,', 'parser.y', 22)
311
+ def _reduce_11(val, _values, result)
312
+ result = Comparison.new(:left => val[0], :right => val[2], :operator => val[1].to_sym)
313
+ result
314
+ end
315
+ .,.,
316
+
317
+ # reduce 12 omitted
318
+
319
+ # reduce 13 omitted
320
+
321
+ module_eval(<<'.,.,', 'parser.y', 31)
322
+ def _reduce_14(val, _values, result)
323
+ result = Conditions::Not.new(:value => Comparison.new(:left => val[0], :right => val[3], :operator => :LIKE))
324
+ result
325
+ end
326
+ .,.,
327
+
328
+ module_eval(<<'.,.,', 'parser.y', 32)
329
+ def _reduce_15(val, _values, result)
330
+ result = Comparison.new(:left => val[0], :right => val[2], :operator => :LIKE)
331
+ result
332
+ end
333
+ .,.,
334
+
335
+ # reduce 16 omitted
336
+
337
+ # reduce 17 omitted
338
+
339
+ module_eval(<<'.,.,', 'parser.y', 41)
340
+ def _reduce_18(val, _values, result)
341
+ result = Comparison.new(:left => val[0], :right => val[3], :operator => :'<>')
342
+ result
343
+ end
344
+ .,.,
345
+
346
+ module_eval(<<'.,.,', 'parser.y', 42)
347
+ def _reduce_19(val, _values, result)
348
+ result = Comparison.new(:left => val[0], :right => val[2], :operator => :'=')
349
+ result
350
+ end
351
+ .,.,
352
+
353
+ module_eval(<<'.,.,', 'parser.y', 46)
354
+ def _reduce_20(val, _values, result)
355
+ result = Conditions::Not.new(:value => In.new(:left => val[0], :right => Atoms::InValues.new(:values => val[4])))
356
+ result
357
+ end
358
+ .,.,
359
+
360
+ module_eval(<<'.,.,', 'parser.y', 47)
361
+ def _reduce_21(val, _values, result)
362
+ result = In.new(:left => val[0], :right => Atoms::InValues.new(:values => val[3]))
363
+ result
364
+ end
365
+ .,.,
366
+
367
+ module_eval(<<'.,.,', 'parser.y', 51)
368
+ def _reduce_22(val, _values, result)
369
+ result = [val[0]]
370
+ result
371
+ end
372
+ .,.,
373
+
374
+ module_eval(<<'.,.,', 'parser.y', 52)
375
+ def _reduce_23(val, _values, result)
376
+ result = val[0].concat([val[2]])
377
+ result
378
+ end
379
+ .,.,
380
+
381
+ module_eval(<<'.,.,', 'parser.y', 58)
382
+ def _reduce_24(val, _values, result)
383
+ result = Atoms::Scalar.new(:left => val[0], :right => val[2], :operation => :'+')
384
+ result
385
+ end
386
+ .,.,
387
+
388
+ module_eval(<<'.,.,', 'parser.y', 59)
389
+ def _reduce_25(val, _values, result)
390
+ result = Atoms::Scalar.new(:left => val[0], :right => val[2], :operation => :'-')
391
+ result
392
+ end
393
+ .,.,
394
+
395
+ module_eval(<<'.,.,', 'parser.y', 60)
396
+ def _reduce_26(val, _values, result)
397
+ result = Atoms::Scalar.new(:left => val[0], :right => val[2], :operation => :'*')
398
+ result
399
+ end
400
+ .,.,
401
+
402
+ module_eval(<<'.,.,', 'parser.y', 61)
403
+ def _reduce_27(val, _values, result)
404
+ result = Atoms::Scalar.new(:left => val[0], :right => val[2], :operation => :'/')
405
+ result
406
+ end
407
+ .,.,
408
+
409
+ module_eval(<<'.,.,', 'parser.y', 62)
410
+ def _reduce_28(val, _values, result)
411
+ result = Atoms::UnaryScalar.new(:value => val[1], :operation => :'+')
412
+ result
413
+ end
414
+ .,.,
415
+
416
+ module_eval(<<'.,.,', 'parser.y', 63)
417
+ def _reduce_29(val, _values, result)
418
+ result = Atoms::UnaryScalar.new(:value => val[1], :operation => :'-')
419
+ result
420
+ end
421
+ .,.,
422
+
423
+ # reduce 30 omitted
424
+
425
+ # reduce 31 omitted
426
+
427
+ # reduce 32 omitted
428
+
429
+ # reduce 33 omitted
430
+
431
+ module_eval(<<'.,.,', 'parser.y', 74)
432
+ def _reduce_34(val, _values, result)
433
+ result = Atoms::Literal.new(:value => val[0], :type => :string)
434
+ result
435
+ end
436
+ .,.,
437
+
438
+ module_eval(<<'.,.,', 'parser.y', 75)
439
+ def _reduce_35(val, _values, result)
440
+ result = Atoms::Literal.new(:value => val[0], :type => :float)
441
+ result
442
+ end
443
+ .,.,
444
+
445
+ module_eval(<<'.,.,', 'parser.y', 76)
446
+ def _reduce_36(val, _values, result)
447
+ result = Atoms::Literal.new(:value => val[0], :type => :int)
448
+ result
449
+ end
450
+ .,.,
451
+
452
+ module_eval(<<'.,.,', 'parser.y', 77)
453
+ def _reduce_37(val, _values, result)
454
+ result = Atoms::Literal.new(:value => val[0], :type => :datetime)
455
+ result
456
+ end
457
+ .,.,
458
+
459
+ module_eval(<<'.,.,', 'parser.y', 81)
460
+ def _reduce_38(val, _values, result)
461
+ result = Atoms::Column.new(:name => val[0])
462
+ result
463
+ end
464
+ .,.,
465
+
466
+ module_eval(<<'.,.,', 'parser.y', 82)
467
+ def _reduce_39(val, _values, result)
468
+ result = Atoms::Column.new(:name => val[0], :table=> val[2])
469
+ result
470
+ end
471
+ .,.,
472
+
473
+ module_eval(<<'.,.,', 'parser.y', 83)
474
+ def _reduce_40(val, _values, result)
475
+ result = Atoms::Column.new(:name => val[4], :table=> val[2], :space => val[0])
476
+ result
477
+ end
478
+ .,.,
479
+
480
+ def _reduce_none(val, _values, result)
481
+ val[0]
482
+ end
483
+
484
+ end # class Parser
485
+ end # module SQLSearch
@@ -0,0 +1,66 @@
1
+ class SQLSearch::Parser
2
+
3
+ option
4
+ ignorecase
5
+
6
+ macro
7
+ BLANK [\ \t]+
8
+ STRING [^']+
9
+ APPROXNUM {INTNUM}\.{INTNUM}
10
+ INTNUM \d+
11
+ COMPARISON (<>|=|[<][=]|[<]|[>][=]|[>])
12
+
13
+ NAME [A-z_]([A-z0-9_]*)
14
+
15
+ IS is
16
+ NOT not
17
+ NULLX null
18
+ IN in
19
+ OR or
20
+ AND and
21
+ BETWEEN between
22
+
23
+ YEARS \d+
24
+ MONTHS \d{2}
25
+ DAYS \d{2}
26
+ HOURS \d{2}
27
+ MINUTES \d{2}
28
+ SECONDS \d{2}
29
+ UTC_OFFSET ([+-]{HOURS}:{MINUTES}|Z)
30
+ TIME {YEARS}-{MONTHS}-{DAYS}T{HOURS}:{MINUTES}:{SECONDS}{UTC_OFFSET}
31
+
32
+ rule
33
+ {BLANK}
34
+ {APPROXNUM} { [:APPROXNUM, text.to_f] }
35
+ {INTNUM} { [:INTNUM, text.to_i] }
36
+ '{TIME}' { [:TIME, DateTime.iso8601(text[1...-1])] }
37
+ '{STRING}' { [:STRING, text[1...-1]] }
38
+ IS { [:IS, text] }
39
+ NOT { [:NOT, text] }
40
+ NULL { [:NULL, text.upcase] }
41
+ IN { [:IN, text] }
42
+ OR { [:OR, text] }
43
+ AND { [:AND, text] }
44
+ BETWEEN { [:BETWEEN, text] }
45
+ LIKE { [:LIKE, text] }
46
+ {COMPARISON} { [:COMPARISON, text] }
47
+ {NAME} { [:NAME, text] }
48
+ \( { [:LPAREN, text] }
49
+ \) { [:RPAREN, text] }
50
+ \. { [:DOT, text] }
51
+ \, { [:COMMA, text] }
52
+ \+ { [:ADD, text] }
53
+ \- { [:SUBTRACT, text] }
54
+ \/ { [:DIVIDE, text] }
55
+ \* { [:MULTIPLY, text] }
56
+ inner
57
+
58
+ def tokenize(code)
59
+ scan_setup(code)
60
+ tokens = []
61
+ while token = next_token
62
+ tokens << token
63
+ end
64
+ tokens
65
+ end
66
+ end
@@ -0,0 +1,148 @@
1
+ #--
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by rex 1.0.5
4
+ # from lexical definition file "lib/sql_search/parser.rex".
5
+ #++
6
+
7
+ require 'racc/parser'
8
+ class SQLSearch::Parser < Racc::Parser
9
+ require 'strscan'
10
+
11
+ class ScanError < StandardError ; end
12
+
13
+ attr_reader :lineno
14
+ attr_reader :filename
15
+ attr_accessor :state
16
+
17
+ def scan_setup(str)
18
+ @ss = StringScanner.new(str)
19
+ @lineno = 1
20
+ @state = nil
21
+ end
22
+
23
+ def action
24
+ yield
25
+ end
26
+
27
+ def scan_str(str)
28
+ scan_setup(str)
29
+ do_parse
30
+ end
31
+ alias :scan :scan_str
32
+
33
+ def load_file( filename )
34
+ @filename = filename
35
+ open(filename, "r") do |f|
36
+ scan_setup(f.read)
37
+ end
38
+ end
39
+
40
+ def scan_file( filename )
41
+ load_file(filename)
42
+ do_parse
43
+ end
44
+
45
+
46
+ def next_token
47
+ return if @ss.eos?
48
+
49
+ # skips empty actions
50
+ until token = _next_token or @ss.eos?; end
51
+ token
52
+ end
53
+
54
+ def _next_token
55
+ text = @ss.peek(1)
56
+ @lineno += 1 if text == "\n"
57
+ token = case @state
58
+ when nil
59
+ case
60
+ when (text = @ss.scan(/[ \t]+/i))
61
+ ;
62
+
63
+ when (text = @ss.scan(/\d+\.\d+/i))
64
+ action { [:APPROXNUM, text.to_f] }
65
+
66
+ when (text = @ss.scan(/\d+/i))
67
+ action { [:INTNUM, text.to_i] }
68
+
69
+ when (text = @ss.scan(/'\d+-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}([+-]\d{2}:\d{2}|Z)'/i))
70
+ action { [:TIME, DateTime.iso8601(text[1...-1])] }
71
+
72
+ when (text = @ss.scan(/'[^']+'/i))
73
+ action { [:STRING, text[1...-1]] }
74
+
75
+ when (text = @ss.scan(/IS/i))
76
+ action { [:IS, text] }
77
+
78
+ when (text = @ss.scan(/NOT/i))
79
+ action { [:NOT, text] }
80
+
81
+ when (text = @ss.scan(/NULL/i))
82
+ action { [:NULL, text.upcase] }
83
+
84
+ when (text = @ss.scan(/IN/i))
85
+ action { [:IN, text] }
86
+
87
+ when (text = @ss.scan(/OR/i))
88
+ action { [:OR, text] }
89
+
90
+ when (text = @ss.scan(/AND/i))
91
+ action { [:AND, text] }
92
+
93
+ when (text = @ss.scan(/BETWEEN/i))
94
+ action { [:BETWEEN, text] }
95
+
96
+ when (text = @ss.scan(/LIKE/i))
97
+ action { [:LIKE, text] }
98
+
99
+ when (text = @ss.scan(/(<>|=|[<][=]|[<]|[>][=]|[>])/i))
100
+ action { [:COMPARISON, text] }
101
+
102
+ when (text = @ss.scan(/[A-z_]([A-z0-9_]*)/i))
103
+ action { [:NAME, text] }
104
+
105
+ when (text = @ss.scan(/\(/i))
106
+ action { [:LPAREN, text] }
107
+
108
+ when (text = @ss.scan(/\)/i))
109
+ action { [:RPAREN, text] }
110
+
111
+ when (text = @ss.scan(/\./i))
112
+ action { [:DOT, text] }
113
+
114
+ when (text = @ss.scan(/\,/i))
115
+ action { [:COMMA, text] }
116
+
117
+ when (text = @ss.scan(/\+/i))
118
+ action { [:ADD, text] }
119
+
120
+ when (text = @ss.scan(/\-/i))
121
+ action { [:SUBTRACT, text] }
122
+
123
+ when (text = @ss.scan(/\//i))
124
+ action { [:DIVIDE, text] }
125
+
126
+ when (text = @ss.scan(/\*/i))
127
+ action { [:MULTIPLY, text] }
128
+
129
+ else
130
+ text = @ss.string[@ss.pos .. -1]
131
+ raise ScanError, "can not match: '" + text + "'"
132
+ end # if
133
+
134
+ else
135
+ raise ScanError, "undefined state: '" + state.to_s + "'"
136
+ end # case state
137
+ token
138
+ end # def _next_token
139
+
140
+ def tokenize(code)
141
+ scan_setup(code)
142
+ tokens = []
143
+ while token = next_token
144
+ tokens << token
145
+ end
146
+ tokens
147
+ end
148
+ end # class
@@ -0,0 +1,97 @@
1
+ class SQLSearch::Parser
2
+
3
+ rule
4
+ /* search conditions */
5
+
6
+ search_condition:
7
+ search_condition OR search_condition { result = Conditions::Or.new(:left => val[0], :right => val[2]) }
8
+ |search_condition AND search_condition { result = Conditions::And.new(:left => val[0], :right => val[2]) }
9
+ |NOT search_condition { result = Conditions::Not.new(:value => val[1]) }
10
+ |LPAREN search_condition RPAREN
11
+ |predicate
12
+ ;
13
+
14
+ predicate:
15
+ comparison_predicate
16
+ |between_predicate
17
+ |like_predicate
18
+ |test_for_null
19
+ |in_predicate
20
+ ;
21
+
22
+ comparison_predicate:
23
+ scalar_exp COMPARISON scalar_exp { result = Comparison.new(:left => val[0], :right => val[2], :operator => val[1].to_sym) }
24
+ ;
25
+
26
+ between_predicate:
27
+ scalar_exp NOT BETWEEN scalar_exp AND scalar_exp
28
+ |scalar_exp BETWEEN scalar_exp AND scalar_exp
29
+ ;
30
+
31
+ like_predicate:
32
+ scalar_exp NOT LIKE atom opt_escape { result = Conditions::Not.new(:value => Comparison.new(:left => val[0], :right => val[3], :operator => :LIKE)) }
33
+ |scalar_exp LIKE atom opt_escape { result = Comparison.new(:left => val[0], :right => val[2], :operator => :LIKE) }
34
+ ;
35
+
36
+ opt_escape:
37
+ /* empty */
38
+ |ESCAPE atom
39
+ ;
40
+
41
+ test_for_null:
42
+ column_ref IS NOT NULL { result = Comparison.new(:left => val[0], :right => val[3], :operator => :'<>') }
43
+ |column_ref IS NULL { result = Comparison.new(:left => val[0], :right => val[2], :operator => :'=') }
44
+ ;
45
+
46
+ in_predicate:
47
+ scalar_exp NOT IN LPAREN atom_commalist RPAREN { result = Conditions::Not.new(:value => In.new(:left => val[0], :right => Atoms::InValues.new(:values => val[4]))) }
48
+ |scalar_exp IN LPAREN atom_commalist RPAREN { result = In.new(:left => val[0], :right => Atoms::InValues.new(:values => val[3])) }
49
+ ;
50
+
51
+ atom_commalist:
52
+ atom { result = [val[0]] }
53
+ |atom_commalist COMMA atom { result = val[0].concat([val[2]]) }
54
+ ;
55
+
56
+ /* scalar expressions */
57
+
58
+ scalar_exp:
59
+ scalar_exp ADD scalar_exp { result = Atoms::Scalar.new(:left => val[0], :right => val[2], :operation => :'+')}
60
+ |scalar_exp SUBTRACT scalar_exp { result = Atoms::Scalar.new(:left => val[0], :right => val[2], :operation => :'-')}
61
+ |scalar_exp MULTIPLY scalar_exp { result = Atoms::Scalar.new(:left => val[0], :right => val[2], :operation => :'*')}
62
+ |scalar_exp DIVIDE scalar_exp { result = Atoms::Scalar.new(:left => val[0], :right => val[2], :operation => :'/')}
63
+ |ADD scalar_exp { result = Atoms::UnaryScalar.new(:value => val[1], :operation => :'+')}
64
+ |SUBTRACT scalar_exp { result = Atoms::UnaryScalar.new(:value => val[1], :operation => :'-')}
65
+ |atom
66
+ |column_ref
67
+ |LPAREN scalar_exp RPAREN
68
+ ;
69
+
70
+ atom:
71
+ literal
72
+ ;
73
+
74
+ literal:
75
+ STRING { result = Atoms::Literal.new(:value => val[0], :type => :string) }
76
+ |APPROXNUM { result = Atoms::Literal.new(:value => val[0], :type => :float) }
77
+ |INTNUM { result = Atoms::Literal.new(:value => val[0], :type => :int) }
78
+ |TIME { result = Atoms::Literal.new(:value => val[0], :type => :datetime) }
79
+ ;
80
+
81
+ column_ref:
82
+ NAME { result = Atoms::Column.new(:name => val[0]) }
83
+ |NAME DOT NAME { result = Atoms::Column.new(:name => val[0], :table=> val[2]) }
84
+ |NAME DOT NAME DOT NAME { result = Atoms::Column.new(:name => val[4], :table=> val[2], :space => val[0]) }
85
+ ;
86
+
87
+ end
88
+
89
+ ---- header
90
+ require 'date'
91
+ require_relative 'parser.rex.rb'
92
+
93
+ ---- inner
94
+ def parse(input)
95
+ scan_str(input)
96
+ end
97
+
@@ -0,0 +1,3 @@
1
+ module SQLSearch
2
+ VERSION = '0.0.2'
3
+ end
@@ -0,0 +1,126 @@
1
+ module SQLSearch
2
+ module Conditions
3
+ class And
4
+ attr_reader :left, :right
5
+ def initialize options
6
+ @left = options[:left]; @right = options[:right]
7
+ end
8
+
9
+ def to_s
10
+ "(#{left}) AND (#{right})"
11
+ end
12
+ end
13
+
14
+ class Or
15
+ attr_reader :left, :right
16
+ def initialize options
17
+ @left = options[:left]; @right = options[:right]
18
+ end
19
+
20
+ def to_s
21
+ "(#{left}) OR (#{right})"
22
+ end
23
+ end
24
+
25
+ class Not
26
+ attr_reader :value
27
+ def initialize options
28
+ @value = options[:value]
29
+ end
30
+
31
+ def to_s
32
+ "NOT(#{value})"
33
+ end
34
+ end
35
+ end
36
+
37
+ class Comparison
38
+ attr_reader :left, :right, :operator
39
+
40
+ def initialize options
41
+ @left = options[:left]
42
+ @right = options[:right]
43
+ @operator = options[:operator]
44
+ end
45
+
46
+ def to_s
47
+ "#{left} #{operator} #{right}"
48
+ end
49
+ end
50
+
51
+ class In < Comparison
52
+ def initialize options
53
+ super options
54
+ @operator = :IN
55
+ end
56
+ end
57
+
58
+ module Atoms
59
+ class InValues
60
+ attr_reader :values
61
+ def initialize options
62
+ @values = options[:values]
63
+ end
64
+
65
+ def to_s
66
+ "(#{values.join(', ')})"
67
+ end
68
+ end
69
+
70
+ class Scalar
71
+ attr_reader :left, :right, :operation
72
+ def initialize options
73
+ @left = options[:left]
74
+ @right = options[:right]
75
+ @operation = options[:operation]
76
+ end
77
+
78
+ def to_s
79
+ "#{left} #{operation} #{right}"
80
+ end
81
+ end
82
+
83
+ class UnaryScalar < Scalar
84
+ attr_reader :value, :operation
85
+ def initialize options
86
+ @value = options[:value]
87
+ @operation = options[:operation]
88
+ end
89
+
90
+ def to_s
91
+ "#{operation}#{value}"
92
+ end
93
+ end
94
+
95
+ class Literal
96
+ attr_reader :value, :type
97
+ def initialize options
98
+ @value = options[:value]
99
+ @type = options[:type]
100
+ end
101
+
102
+ def to_s
103
+ case type
104
+ when :string then "'#{value}'"
105
+ else "#{value}"
106
+ end
107
+ end
108
+ end
109
+
110
+ class Column
111
+ attr_reader :name, :table, :space
112
+
113
+ def initialize options
114
+ @name = options[:name]
115
+ @table = options[:table]
116
+ @space = options[:space]
117
+ end
118
+
119
+ def to_s
120
+ [space,table,name].compact.map { |a| "`#{a}`" }.join('.')
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ require 'sql_search/parser.racc.rb'
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sql_search_parser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Antoine Niek
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rexical
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: racc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Simple SQL search conditions parser (where clause)
70
+ email: antoineniek@gmail.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - LICENSE
76
+ - README.md
77
+ - Rakefile
78
+ - lib/sql_search_parser.rb
79
+ - lib/sql_search/parser.rex.rb
80
+ - lib/sql_search/parser.y
81
+ - lib/sql_search/parser.rex
82
+ - lib/sql_search/version.rb
83
+ - lib/sql_search/parser.racc.rb
84
+ homepage: https://github.com/zapo/sql_search_parser
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.0.14
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Simple SQL search conditions parser (where clause)
108
+ test_files: []