twowaysql 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -11,21 +11,19 @@ module TwoWaySQL
11
11
 
12
12
  class Parser < Racc::Parser
13
13
 
14
- module_eval <<'..end lib/twowaysql/parser.y modeval..id33db4a3791', 'lib/twowaysql/parser.y', 138
14
+ module_eval <<'..end lib/twowaysql/parser.y modeval..idd0cee34b5c', 'lib/twowaysql/parser.y', 134
15
15
 
16
16
  require 'strscan'
17
17
 
18
18
  def initialize(opts={})
19
19
  opts = {
20
- :debug => true,
20
+ :debug => false,
21
21
  :preserve_space => true,
22
- :preserve_comment => true,
23
- :preserve_eol => true
22
+ :preserve_comment => false
24
23
  }.merge(opts)
25
24
  @yydebug = opts[:debug]
26
25
  @preserve_space = opts[:preserve_space]
27
26
  @preserve_comment = opts[:preserve_comment]
28
- @preserve_eol = opts[:preserve_eol]
29
27
  @num_questions = 0
30
28
  end
31
29
 
@@ -36,28 +34,30 @@ BIND_VARIABLE_PATTERN = /\A#{BEGIN_BIND_VARIABLE}\s*/
36
34
  PAREN_BIND_VARIABLE_PATTERN = /\A#{BEGIN_BIND_VARIABLE}\s*#{PAREN_EXAMPLE}/
37
35
  EMBED_VARIABLE_PATTERN = /\A(\/|\#)\*\$([^\*]+)\*\1\s*/
38
36
 
39
- CONDITIONAL_PATTERN = /\A(\/|\#)\*(IF)\s+([^\*]+)\s*\*\1/
40
- BEGIN_END_PATTERN = /\A(\/|\#)\*(BEGIN|END)\s*\*\1/
41
- STRING_LITERAL_PATTERN = /\A(\'(?:[^\']+|\'\')*\')/ ## quoted string
42
- SPLIT_TOKEN_PATTERN = /\A(\S+?)(?=\s*(?:(?:\/|\#)\*|-{2,}|\(|\)|\,))/ ## stop on delimiters --,/*,#*,',',(,)
43
- ELSE_PATTERN = /\A\-{2,}\s*ELSE\s*/
44
- AND_PATTERN = /\A(\s*AND\s+)/i
45
- OR_PATTERN = /\A(\s*OR\s+)/i
46
- LITERAL_PATTERN = /\A([^;\s]+)/
47
- SPACES_PATTERN = /\A(\s+)/
48
- QUESTION_PATTERN = /\A\?/
49
- COMMA_PATTERN = /\A\,/
50
- LPAREN_PATTERN = /\A\(/
51
- RPAREN_PATTERN = /\A\)/
52
- ACTUAL_COMMENT_PATTERN = /\A(\/|\#)\*\s+(.+)\s*\*\1/ ## start with spaces
37
+ CONDITIONAL_PATTERN = /\A(\/|\#)\*(IF)\s+([^\*]+)\s*\*\1/
38
+ BEGIN_END_PATTERN = /\A(\/|\#)\*(BEGIN|END)\s*\*\1/
39
+ STRING_LITERAL_PATTERN = /\A(\'(?:[^\']+|\'\')*\')/ ## quoted string
40
+ SPLIT_TOKEN_PATTERN = /\A(\S+?)(?=\s*(?:(?:\/|\#)\*|-{2,}|\(|\)|\,))/ ## stop on delimiters --,/*,#*,',',(,)
41
+ LITERAL_PATTERN = /\A([^;\s]+)/
42
+ SPACES_PATTERN = /\A(\s+)/
43
+ QUESTION_PATTERN = /\A\?/
44
+ COMMA_PATTERN = /\A\,/
45
+ LPAREN_PATTERN = /\A\(/
46
+ RPAREN_PATTERN = /\A\)/
47
+ ACTUAL_COMMENT_PATTERN = /\A(\/|\#)\*(\s{1,}(?:.*?))\*\1/m ## start with spaces
53
48
  SEMICOLON_AT_INPUT_END_PATTERN = /\A\;\s*\Z/
54
49
  UNMATCHED_COMMENT_START_PATTERN = /\A(?:(?:\/|\#)\*)/
55
50
 
51
+ #TODO: remove trailing spaces for S2Dao compatibility, but this spec sometimes causes SQL bugs...
52
+ ELSE_PATTERN = /\A\-{2,}\s*ELSE\s*/
53
+ AND_PATTERN = /\A(\ *AND)\b/i
54
+ OR_PATTERN = /\A(\ *OR)\b/i
55
+
56
56
 
57
57
  def parse( io )
58
58
  @q = []
59
- io.each_line do |line|
60
- s = StringScanner.new(line.rstrip)
59
+ io.each_line(nil) do |whole|
60
+ s = StringScanner.new(whole)
61
61
  until s.eos? do
62
62
  case
63
63
  when s.scan(AND_PATTERN)
@@ -65,7 +65,7 @@ def parse( io )
65
65
  when s.scan(OR_PATTERN)
66
66
  @q.push [ :OR, s[1] ]
67
67
  when s.scan(SPACES_PATTERN)
68
- @q.push [ :SPACES, s[1] ] if @preserve_space
68
+ @q.push [ :SPACES, s[1] ]
69
69
  when s.scan(QUESTION_PATTERN)
70
70
  @q.push [ :QUESTION, nil ]
71
71
  when s.scan(COMMA_PATTERN)
@@ -77,7 +77,7 @@ def parse( io )
77
77
  when s.scan(ELSE_PATTERN)
78
78
  @q.push [ :ELSE, nil ]
79
79
  when s.scan(ACTUAL_COMMENT_PATTERN)
80
- @q.push [ :ACTUAL_COMMENT, s[2] ] if @preserve_comment
80
+ @q.push [ :ACTUAL_COMMENT, [s[1], s[2]] ] if @preserve_comment
81
81
  when s.scan(BEGIN_END_PATTERN)
82
82
  @q.push [ s[2].intern, nil ]
83
83
  when s.scan(CONDITIONAL_PATTERN)
@@ -103,7 +103,6 @@ def parse( io )
103
103
  end
104
104
  end
105
105
 
106
- @q.push [ :EOL, nil ] if @preserve_eol
107
106
  end
108
107
 
109
108
  @q.push [ false, nil ]
@@ -115,109 +114,108 @@ end
115
114
  def next_token
116
115
  @q.shift
117
116
  end
118
- ..end lib/twowaysql/parser.y modeval..id33db4a3791
117
+ ..end lib/twowaysql/parser.y modeval..idd0cee34b5c
119
118
 
120
119
  ##### racc 1.4.5 generates ###
121
120
 
122
121
  racc_reduce_table = [
123
122
  0, 0, :racc_error,
124
- 1, 21, :_reduce_1,
125
- 0, 22, :_reduce_2,
126
- 2, 22, :_reduce_3,
127
- 1, 23, :_reduce_none,
123
+ 1, 20, :_reduce_1,
124
+ 0, 21, :_reduce_2,
125
+ 2, 21, :_reduce_3,
126
+ 1, 22, :_reduce_none,
127
+ 1, 22, :_reduce_none,
128
+ 1, 22, :_reduce_none,
129
+ 3, 25, :_reduce_7,
130
+ 4, 24, :_reduce_8,
131
+ 2, 27, :_reduce_9,
132
+ 0, 27, :_reduce_10,
133
+ 1, 26, :_reduce_none,
134
+ 1, 26, :_reduce_none,
135
+ 1, 26, :_reduce_none,
136
+ 2, 28, :_reduce_14,
137
+ 2, 29, :_reduce_15,
138
+ 1, 23, :_reduce_16,
139
+ 1, 23, :_reduce_17,
140
+ 1, 23, :_reduce_18,
141
+ 1, 23, :_reduce_19,
142
+ 1, 23, :_reduce_20,
143
+ 1, 23, :_reduce_21,
144
+ 1, 23, :_reduce_22,
145
+ 1, 23, :_reduce_23,
146
+ 1, 23, :_reduce_24,
147
+ 1, 23, :_reduce_25,
128
148
  1, 23, :_reduce_none,
129
149
  1, 23, :_reduce_none,
130
- 3, 26, :_reduce_7,
131
- 4, 25, :_reduce_8,
132
- 2, 28, :_reduce_9,
133
- 0, 28, :_reduce_10,
134
- 1, 27, :_reduce_none,
135
- 1, 27, :_reduce_none,
136
- 1, 27, :_reduce_none,
137
- 2, 29, :_reduce_14,
138
- 2, 30, :_reduce_15,
139
- 1, 24, :_reduce_16,
140
- 1, 24, :_reduce_17,
141
- 1, 24, :_reduce_18,
142
- 1, 24, :_reduce_19,
143
- 1, 24, :_reduce_20,
144
- 1, 24, :_reduce_21,
145
- 1, 24, :_reduce_22,
146
- 1, 24, :_reduce_23,
147
- 1, 24, :_reduce_24,
148
- 1, 24, :_reduce_25,
149
- 1, 24, :_reduce_26,
150
- 1, 24, :_reduce_none,
151
- 1, 24, :_reduce_none,
152
- 2, 31, :_reduce_29,
153
- 3, 31, :_reduce_30,
154
- 2, 31, :_reduce_31,
155
- 3, 31, :_reduce_32,
156
- 1, 31, :_reduce_33,
157
- 2, 32, :_reduce_34,
158
- 3, 32, :_reduce_35 ]
159
-
160
- racc_reduce_n = 36
161
-
162
- racc_shift_n = 49
150
+ 2, 30, :_reduce_28,
151
+ 3, 30, :_reduce_29,
152
+ 2, 30, :_reduce_30,
153
+ 3, 30, :_reduce_31,
154
+ 1, 30, :_reduce_32,
155
+ 2, 31, :_reduce_33,
156
+ 3, 31, :_reduce_34 ]
157
+
158
+ racc_reduce_n = 35
159
+
160
+ racc_shift_n = 48
163
161
 
164
162
  racc_action_table = [
165
- 7, 36, 12, 37, 16, 18, 20, 22, 24, 3,
166
- 4, 6, 9, 11, 14, 15, 17, 19, 7, 46,
167
- 12, 40, 16, 18, 20, 22, 24, 3, 4, 6,
168
- 9, 11, 14, 15, 17, 19, 7, 48, 12, 38,
169
- 16, 18, 20, 22, 24, 3, 4, 6, 9, 11,
170
- 14, 15, 17, 19, 7, 39, 12, 25, 16, 18,
171
- 20, 22, 24, 3, 4, 6, 9, 11, 14, 15,
172
- 17, 19, 7, nil, 12, nil, 16, 18, 20, 22,
173
- 24, 3, 4, 6, 9, 11, 14, 15, 17, 19,
174
- 33, 34, 35, 29, 30, 29, 30, 44, 45 ]
163
+ 9, 36, 14, 37, 17, 19, 21, 23, 24, 4,
164
+ 6, 8, 11, 13, 15, 16, 18, 9, 39, 14,
165
+ 45, 17, 19, 21, 23, 24, 4, 6, 8, 11,
166
+ 13, 15, 16, 18, 9, 47, 14, 25, 17, 19,
167
+ 21, 23, 24, 4, 6, 8, 11, 13, 15, 16,
168
+ 18, 9, 38, 14, 3, 17, 19, 21, 23, 24,
169
+ 4, 6, 8, 11, 13, 15, 16, 18, 9, nil,
170
+ 14, nil, 17, 19, 21, 23, 24, 4, 6, 8,
171
+ 11, 13, 15, 16, 18, 33, 34, 35, 28, 30,
172
+ 28, 30, 43, 44 ]
175
173
 
176
174
  racc_action_check = [
177
- 1, 19, 1, 19, 1, 1, 1, 1, 1, 1,
178
- 1, 1, 1, 1, 1, 1, 1, 1, 43, 37,
179
- 43, 28, 43, 43, 43, 43, 43, 43, 43, 43,
180
- 43, 43, 43, 43, 43, 43, 42, 41, 42, 25,
181
- 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
182
- 42, 42, 42, 42, 26, 26, 26, 2, 26, 26,
183
- 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
184
- 26, 26, 27, nil, 27, nil, 27, 27, 27, 27,
185
- 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
186
- 15, 15, 15, 12, 12, 40, 40, 35, 35 ]
175
+ 42, 18, 42, 18, 42, 42, 42, 42, 42, 42,
176
+ 42, 42, 42, 42, 42, 42, 42, 2, 27, 2,
177
+ 37, 2, 2, 2, 2, 2, 2, 2, 2, 2,
178
+ 2, 2, 2, 2, 41, 40, 41, 3, 41, 41,
179
+ 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
180
+ 41, 26, 26, 26, 1, 26, 26, 26, 26, 26,
181
+ 26, 26, 26, 26, 26, 26, 26, 26, 32, nil,
182
+ 32, nil, 32, 32, 32, 32, 32, 32, 32, 32,
183
+ 32, 32, 32, 32, 32, 15, 15, 15, 39, 39,
184
+ 14, 14, 35, 35 ]
187
185
 
188
186
  racc_action_pointer = [
189
- nil, -2, 57, nil, nil, nil, nil, nil, nil, nil,
190
- nil, nil, 87, nil, nil, 82, nil, nil, nil, -7,
191
- nil, nil, nil, nil, nil, 39, 52, 70, 16, nil,
192
- nil, nil, nil, nil, nil, 89, nil, 11, nil, nil,
193
- 89, 34, 34, 16, nil, nil, nil, nil, nil ]
187
+ nil, 54, 15, 37, nil, nil, nil, nil, nil, nil,
188
+ nil, nil, nil, nil, 84, 77, nil, nil, -7, nil,
189
+ nil, nil, nil, nil, nil, nil, 49, 13, nil, nil,
190
+ nil, nil, 66, nil, nil, 84, nil, 12, nil, 82,
191
+ 32, 32, -2, nil, nil, nil, nil, nil ]
194
192
 
195
193
  racc_action_default = [
196
- -2, -1, -36, -21, -22, -3, -23, -2, -4, -24,
197
- -5, -25, -2, -6, -26, -36, -18, -33, -19, -36,
198
- -16, -27, -17, -28, -20, -36, -36, -13, -10, -2,
199
- -2, -11, -12, -31, -29, -36, -34, -36, 49, -7,
200
- -2, -36, -14, -15, -32, -30, -35, -9, -8 ]
194
+ -2, -35, -1, -35, -21, -3, -22, -4, -23, -2,
195
+ -5, -24, -6, -25, -2, -35, -32, -18, -35, -19,
196
+ -26, -16, -27, -17, -20, 48, -35, -10, -2, -11,
197
+ -2, -12, -13, -30, -28, -35, -33, -35, -7, -2,
198
+ -35, -14, -15, -31, -29, -34, -9, -8 ]
201
199
 
202
200
  racc_goto_table = [
203
- 1, 2, 41, 28, nil, nil, nil, 26, nil, nil,
201
+ 2, 27, 1, 40, nil, nil, nil, nil, nil, 26,
204
202
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
205
- nil, nil, nil, nil, nil, nil, nil, nil, nil, 42,
206
- 43, 47 ]
203
+ nil, nil, nil, nil, nil, nil, 46, nil, 41, nil,
204
+ 42 ]
207
205
 
208
206
  racc_goto_check = [
209
- 2, 1, 8, 7, nil, nil, nil, 2, nil, nil,
207
+ 2, 7, 1, 8, nil, nil, nil, nil, nil, 2,
210
208
  nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
211
- nil, nil, nil, nil, nil, nil, nil, nil, nil, 2,
212
- 2, 7 ]
209
+ nil, nil, nil, nil, nil, nil, 7, nil, 2, nil,
210
+ 2 ]
213
211
 
214
212
  racc_goto_pointer = [
215
- nil, 1, 0, nil, nil, nil, nil, -9, -26, nil,
213
+ nil, 2, 0, nil, nil, nil, nil, -13, -24, nil,
216
214
  nil, nil, nil ]
217
215
 
218
216
  racc_goto_default = [
219
- nil, nil, 27, 5, 8, 10, 13, nil, nil, 31,
220
- 32, 21, 23 ]
217
+ nil, nil, 32, 5, 7, 10, 12, nil, nil, 29,
218
+ 31, 20, 22 ]
221
219
 
222
220
  racc_token_table = {
223
221
  false => 0,
@@ -236,14 +234,13 @@ racc_token_table = {
236
234
  :RPAREN => 13,
237
235
  :QUESTION => 14,
238
236
  :ACTUAL_COMMENT => 15,
239
- :EOL => 16,
240
- :BIND_VARIABLE => 17,
241
- :PAREN_BIND_VARIABLE => 18,
242
- :EMBED_VARIABLE => 19 }
237
+ :BIND_VARIABLE => 16,
238
+ :PAREN_BIND_VARIABLE => 17,
239
+ :EMBED_VARIABLE => 18 }
243
240
 
244
241
  racc_use_result_var = true
245
242
 
246
- racc_nt_base = 20
243
+ racc_nt_base = 19
247
244
 
248
245
  Racc_arg = [
249
246
  racc_action_table,
@@ -278,7 +275,6 @@ Racc_token_to_s_table = [
278
275
  'RPAREN',
279
276
  'QUESTION',
280
277
  'ACTUAL_COMMENT',
281
- 'EOL',
282
278
  'BIND_VARIABLE',
283
279
  'PAREN_BIND_VARIABLE',
284
280
  'EMBED_VARIABLE',
@@ -407,7 +403,7 @@ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 71
407
403
 
408
404
  module_eval <<'.,.,', 'lib/twowaysql/parser.y', 75
409
405
  def _reduce_20( val, _values, result )
410
- result = LiteralNode.new( val[0] )
406
+ result = WhiteSpaceNode.new( val[0], @preserve_space )
411
407
  result
412
408
  end
413
409
  .,.,
@@ -443,21 +439,21 @@ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 92
443
439
 
444
440
  module_eval <<'.,.,', 'lib/twowaysql/parser.y', 96
445
441
  def _reduce_25( val, _values, result )
446
- result = CommentNode.new( val[0] )
442
+ result = ActualCommentNode.new( val[0][0] , val[0][1] )
447
443
  result
448
444
  end
449
445
  .,.,
450
446
 
451
- module_eval <<'.,.,', 'lib/twowaysql/parser.y', 100
452
- def _reduce_26( val, _values, result )
453
- result = EolNode.new
454
- result
455
- end
456
- .,.,
447
+ # reduce 26 omitted
457
448
 
458
449
  # reduce 27 omitted
459
450
 
460
- # reduce 28 omitted
451
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 103
452
+ def _reduce_28( val, _values, result )
453
+ result = BindVariableNode.new( val[0] )
454
+ result
455
+ end
456
+ .,.,
461
457
 
462
458
  module_eval <<'.,.,', 'lib/twowaysql/parser.y', 107
463
459
  def _reduce_29( val, _values, result )
@@ -482,14 +478,14 @@ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 115
482
478
 
483
479
  module_eval <<'.,.,', 'lib/twowaysql/parser.y', 119
484
480
  def _reduce_32( val, _values, result )
485
- result = BindVariableNode.new( val[0] )
481
+ result = ParenBindVariableNode.new( val[0] )
486
482
  result
487
483
  end
488
484
  .,.,
489
485
 
490
- module_eval <<'.,.,', 'lib/twowaysql/parser.y', 123
486
+ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 124
491
487
  def _reduce_33( val, _values, result )
492
- result = ParenBindVariableNode.new( val[0] )
488
+ result = EmbedVariableNode.new( val[0] )
493
489
  result
494
490
  end
495
491
  .,.,
@@ -501,13 +497,6 @@ module_eval <<'.,.,', 'lib/twowaysql/parser.y', 128
501
497
  end
502
498
  .,.,
503
499
 
504
- module_eval <<'.,.,', 'lib/twowaysql/parser.y', 132
505
- def _reduce_35( val, _values, result )
506
- result = EmbedVariableNode.new( val[0] )
507
- result
508
- end
509
- .,.,
510
-
511
500
  def _reduce_none( val, _values, result )
512
501
  result
513
502
  end
@@ -71,7 +71,7 @@ primary : IDENT
71
71
  }
72
72
  | SPACES
73
73
  {
74
- result = LiteralNode.new( val[0] )
74
+ result = WhiteSpaceNode.new( val[0], @preserve_space )
75
75
  }
76
76
  | COMMA
77
77
  {
@@ -92,11 +92,7 @@ primary : IDENT
92
92
  }
93
93
  | ACTUAL_COMMENT
94
94
  {
95
- result = CommentNode.new( val[0] )
96
- }
97
- | EOL
98
- {
99
- result = EolNode.new
95
+ result = ActualCommentNode.new( val[0][0] , val[0][1] )
100
96
  }
101
97
  | bind_var
102
98
  | embed_var
@@ -140,15 +136,13 @@ require 'strscan'
140
136
 
141
137
  def initialize(opts={})
142
138
  opts = {
143
- :debug => true,
139
+ :debug => false,
144
140
  :preserve_space => true,
145
- :preserve_comment => true,
146
- :preserve_eol => true
141
+ :preserve_comment => false
147
142
  }.merge(opts)
148
143
  @yydebug = opts[:debug]
149
144
  @preserve_space = opts[:preserve_space]
150
145
  @preserve_comment = opts[:preserve_comment]
151
- @preserve_eol = opts[:preserve_eol]
152
146
  @num_questions = 0
153
147
  end
154
148
 
@@ -159,28 +153,30 @@ BIND_VARIABLE_PATTERN = /\A#{BEGIN_BIND_VARIABLE}\s*/
159
153
  PAREN_BIND_VARIABLE_PATTERN = /\A#{BEGIN_BIND_VARIABLE}\s*#{PAREN_EXAMPLE}/
160
154
  EMBED_VARIABLE_PATTERN = /\A(\/|\#)\*\$([^\*]+)\*\1\s*/
161
155
 
162
- CONDITIONAL_PATTERN = /\A(\/|\#)\*(IF)\s+([^\*]+)\s*\*\1/
163
- BEGIN_END_PATTERN = /\A(\/|\#)\*(BEGIN|END)\s*\*\1/
164
- STRING_LITERAL_PATTERN = /\A(\'(?:[^\']+|\'\')*\')/ ## quoted string
165
- SPLIT_TOKEN_PATTERN = /\A(\S+?)(?=\s*(?:(?:\/|\#)\*|-{2,}|\(|\)|\,))/ ## stop on delimiters --,/*,#*,',',(,)
166
- ELSE_PATTERN = /\A\-{2,}\s*ELSE\s*/
167
- AND_PATTERN = /\A(\s*AND\s+)/i
168
- OR_PATTERN = /\A(\s*OR\s+)/i
169
- LITERAL_PATTERN = /\A([^;\s]+)/
170
- SPACES_PATTERN = /\A(\s+)/
171
- QUESTION_PATTERN = /\A\?/
172
- COMMA_PATTERN = /\A\,/
173
- LPAREN_PATTERN = /\A\(/
174
- RPAREN_PATTERN = /\A\)/
175
- ACTUAL_COMMENT_PATTERN = /\A(\/|\#)\*\s+(.+)\s*\*\1/ ## start with spaces
156
+ CONDITIONAL_PATTERN = /\A(\/|\#)\*(IF)\s+([^\*]+)\s*\*\1/
157
+ BEGIN_END_PATTERN = /\A(\/|\#)\*(BEGIN|END)\s*\*\1/
158
+ STRING_LITERAL_PATTERN = /\A(\'(?:[^\']+|\'\')*\')/ ## quoted string
159
+ SPLIT_TOKEN_PATTERN = /\A(\S+?)(?=\s*(?:(?:\/|\#)\*|-{2,}|\(|\)|\,))/ ## stop on delimiters --,/*,#*,',',(,)
160
+ LITERAL_PATTERN = /\A([^;\s]+)/
161
+ SPACES_PATTERN = /\A(\s+)/
162
+ QUESTION_PATTERN = /\A\?/
163
+ COMMA_PATTERN = /\A\,/
164
+ LPAREN_PATTERN = /\A\(/
165
+ RPAREN_PATTERN = /\A\)/
166
+ ACTUAL_COMMENT_PATTERN = /\A(\/|\#)\*(\s{1,}(?:.*?))\*\1/m ## start with spaces
176
167
  SEMICOLON_AT_INPUT_END_PATTERN = /\A\;\s*\Z/
177
168
  UNMATCHED_COMMENT_START_PATTERN = /\A(?:(?:\/|\#)\*)/
178
169
 
170
+ #TODO: remove trailing spaces for S2Dao compatibility, but this spec sometimes causes SQL bugs...
171
+ ELSE_PATTERN = /\A\-{2,}\s*ELSE\s*/
172
+ AND_PATTERN = /\A(\ *AND)\b/i
173
+ OR_PATTERN = /\A(\ *OR)\b/i
174
+
179
175
 
180
176
  def parse( io )
181
177
  @q = []
182
- io.each_line do |line|
183
- s = StringScanner.new(line.rstrip)
178
+ io.each_line(nil) do |whole|
179
+ s = StringScanner.new(whole)
184
180
  until s.eos? do
185
181
  case
186
182
  when s.scan(AND_PATTERN)
@@ -188,7 +184,7 @@ def parse( io )
188
184
  when s.scan(OR_PATTERN)
189
185
  @q.push [ :OR, s[1] ]
190
186
  when s.scan(SPACES_PATTERN)
191
- @q.push [ :SPACES, s[1] ] if @preserve_space
187
+ @q.push [ :SPACES, s[1] ]
192
188
  when s.scan(QUESTION_PATTERN)
193
189
  @q.push [ :QUESTION, nil ]
194
190
  when s.scan(COMMA_PATTERN)
@@ -200,7 +196,7 @@ def parse( io )
200
196
  when s.scan(ELSE_PATTERN)
201
197
  @q.push [ :ELSE, nil ]
202
198
  when s.scan(ACTUAL_COMMENT_PATTERN)
203
- @q.push [ :ACTUAL_COMMENT, s[2] ] if @preserve_comment
199
+ @q.push [ :ACTUAL_COMMENT, [s[1], s[2]] ] if @preserve_comment
204
200
  when s.scan(BEGIN_END_PATTERN)
205
201
  @q.push [ s[2].intern, nil ]
206
202
  when s.scan(CONDITIONAL_PATTERN)
@@ -226,7 +222,6 @@ def parse( io )
226
222
  end
227
223
  end
228
224
 
229
- @q.push [ :EOL, nil ] if @preserve_eol
230
225
  end
231
226
 
232
227
  @q.push [ false, nil ]
@@ -1,5 +1,3 @@
1
- require 'forwardable'
2
-
3
1
  module TwoWaySQL
4
2
 
5
3
  # TwoWaySQL::Template represents template object, acts as a Facade for this package.
@@ -64,12 +62,36 @@ module TwoWaySQL
64
62
 
65
63
  # TwoWaySQL::Result represents merge result of template and data.
66
64
  # it contains SQL string with placeholders, and bound variables associated with placeholders.
65
+ #
66
+ # === Usage
67
+ #
68
+ # merged = template.merge(:job => "HOGE", :deptno => 30)
69
+ # merged.sql #=> "SELECT * FROM emp WHERE job = ? AND deptno = ?"
70
+ # merged.bound_variables #=> ["HOGE", 30]
71
+ #
67
72
  class Result
68
- extend Forwardable
69
73
  def initialize(context)
70
74
  @context = context
71
75
  end
72
- def_delegators :@context, :sql, :bound_variables
76
+
77
+ # return merge result SQL with placeholders (question mark).
78
+ #
79
+ # === Return
80
+ # merge result SQL with placeholders
81
+ #
82
+ def sql
83
+ @context.sql
84
+ end
85
+
86
+ # return array of variables which indices are corresponding to placeholders.
87
+ #
88
+ # === Return
89
+ # merge result SQL with placeholders
90
+ #
91
+ def bound_variables
92
+ @context.bound_variables
93
+ end
94
+ alias vars bound_variables
73
95
  end
74
96
 
75
97
  end
@@ -1,8 +1,8 @@
1
1
  module TwoWaySQL
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 2
5
- TINY = 1
4
+ MINOR = 3
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -153,11 +153,26 @@ from
153
153
  /*IF ctx[:id_list] */and id in /*ctx[:id_list]*/(3, 4, 9)/*END*/
154
154
  /*END*/
155
155
  EOS
156
- template = TwoWaySQL::Template.parse(sql)
157
- @result = template.merge(:id_list => [10, 11])
156
+ @template = TwoWaySQL::Template.parse(sql)
158
157
  end
159
158
 
160
- it "sql" do
159
+ it "if both line is true" do
160
+ expected = <<-EOS
161
+ select
162
+ *
163
+ from
164
+ hoge
165
+ where
166
+ name like ?
167
+ and id in (?, ?)
168
+
169
+ EOS
170
+ @result = @template.merge(:name => 'foo%', :id_list => [10, 11])
171
+ @result.sql.should == expected
172
+ @result.bound_variables.should == ['foo%', 10, 11]
173
+ end
174
+
175
+ it "if second line is true" do
161
176
  expected = <<-EOS
162
177
  select
163
178
  *
@@ -165,12 +180,60 @@ from
165
180
  hoge
166
181
  where
167
182
 
168
- id in (?, ?)
183
+ id in (?, ?)
169
184
 
170
185
  EOS
186
+ @result = @template.merge(:id_list => [10, 11])
171
187
  @result.sql.should == expected
172
188
  @result.bound_variables.should == [10, 11]
173
189
  end
190
+
191
+ end
192
+
193
+
194
+
195
+
196
+ describe "examples in website" do
197
+ it do
198
+ # given SQL string with TwoWaySQL comments
199
+ sql = <<-EOS
200
+ SELECT * FROM emp
201
+ /*BEGIN*/WHERE
202
+ /*IF ctx[:job]*/ job = /*ctx[:job]*/'CLERK' /*END*/
203
+ /*IF ctx[:deptno_list]*/ AND deptno IN /*ctx[:deptno_list]*/(20, 30) /*END*/
204
+ /*IF ctx[:age]*/ AND age > /*ctx[:age]*/30 /*END*/
205
+ /*END*/
206
+ /*IF ctx[:order_by] */ ORDER BY /*$ctx[:order_by]*/id /*$ctx[:order]*/ASC /*END*/
207
+ EOS
208
+
209
+
210
+ # parse the SQL to create template object
211
+ template = TwoWaySQL::Template.parse(sql)
212
+
213
+
214
+ # merge data with template
215
+ data = {
216
+ :age => 35,
217
+ :deptno_list => [10,20,30],
218
+ :order_by => 'age',
219
+ :order => 'DESC'
220
+ }
221
+ merged = template.merge(data)
222
+
223
+
224
+ expected_sql = <<-EOS
225
+ SELECT * FROM emp
226
+ WHERE
227
+
228
+ deptno IN (?, ?, ?)
229
+ AND age > ?
230
+
231
+ ORDER BY age DESC
232
+ EOS
233
+
234
+ merged.sql.should == expected_sql #=> true
235
+ merged.bound_variables.should == [10,20,30,35]
236
+ end
174
237
  end
175
238
 
176
239
  end