twowaysql 0.2.1 → 0.3.0
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.
- data/History.txt +12 -4
- data/Manifest.txt +5 -0
- data/README.txt +84 -12
- data/issues/issue-001c53236380a42cd8c5a9099bbcc6ec613919c2.yaml +18 -0
- data/issues/issue-25efcfc383f3b0f6c0e2730ae7c2975bb2b3de26.yaml +15 -3
- data/issues/issue-279105dd0d9f03514d318f5eab5e99c4c2d47fda.yaml +21 -0
- data/issues/issue-28cde89ed3eb306957edc90595b1d16bf43daf42.yaml +26 -0
- data/issues/issue-664986b219202ff1948cab717b56e7540f493561.yaml +5 -1
- data/issues/issue-6daccddf089d11d42bf016897da98f70cf5ab46c.yaml +18 -0
- data/issues/issue-901f65630639507c8b05b466790e9f22256c6450.yaml +15 -3
- data/issues/issue-f1bd40de5458397d9b142ea3e197e5264e0dcdbf.yaml +26 -0
- data/issues/issue-f2b773020b54f839c03d899b38b5113c8fd991df.yaml +15 -3
- data/issues/issue-f64d73ed4f9854f1ded77e6496dbf59cfb3770a7.yaml +10 -2
- data/issues/project.yaml +15 -2
- data/lib/twowaysql/node.rb +16 -6
- data/lib/twowaysql/parser.rb +115 -126
- data/lib/twowaysql/parser.y +24 -29
- data/lib/twowaysql/template.rb +26 -4
- data/lib/twowaysql/version.rb +2 -2
- data/spec/large_sql_spec.rb +67 -4
- data/spec/twowaysql_spec.rb +225 -44
- metadata +7 -2
data/lib/twowaysql/parser.rb
CHANGED
@@ -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..
|
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 =>
|
20
|
+
:debug => false,
|
21
21
|
:preserve_space => true,
|
22
|
-
:preserve_comment =>
|
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
|
40
|
-
BEGIN_END_PATTERN
|
41
|
-
STRING_LITERAL_PATTERN
|
42
|
-
SPLIT_TOKEN_PATTERN
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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 |
|
60
|
-
s = StringScanner.new(
|
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] ]
|
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..
|
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,
|
125
|
-
0,
|
126
|
-
2,
|
127
|
-
1,
|
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
|
-
|
131
|
-
|
132
|
-
2,
|
133
|
-
|
134
|
-
1,
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
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
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
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
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
26, 26, 26, 26, 26, 26, 26, 26,
|
184
|
-
|
185
|
-
|
186
|
-
|
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,
|
190
|
-
nil, nil,
|
191
|
-
nil, nil, nil, nil, nil,
|
192
|
-
nil, nil,
|
193
|
-
|
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, -
|
197
|
-
-5, -
|
198
|
-
-16, -27, -17, -
|
199
|
-
-2, -
|
200
|
-
|
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
|
-
|
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,
|
206
|
-
|
203
|
+
nil, nil, nil, nil, nil, nil, 46, nil, 41, nil,
|
204
|
+
42 ]
|
207
205
|
|
208
206
|
racc_goto_check = [
|
209
|
-
2, 1, 8,
|
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,
|
212
|
-
2
|
209
|
+
nil, nil, nil, nil, nil, nil, 7, nil, 2, nil,
|
210
|
+
2 ]
|
213
211
|
|
214
212
|
racc_goto_pointer = [
|
215
|
-
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,
|
220
|
-
|
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
|
-
:
|
240
|
-
:
|
241
|
-
:
|
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 =
|
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 =
|
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 =
|
442
|
+
result = ActualCommentNode.new( val[0][0] , val[0][1] )
|
447
443
|
result
|
448
444
|
end
|
449
445
|
.,.,
|
450
446
|
|
451
|
-
|
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
|
-
|
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 =
|
481
|
+
result = ParenBindVariableNode.new( val[0] )
|
486
482
|
result
|
487
483
|
end
|
488
484
|
.,.,
|
489
485
|
|
490
|
-
module_eval <<'.,.,', 'lib/twowaysql/parser.y',
|
486
|
+
module_eval <<'.,.,', 'lib/twowaysql/parser.y', 124
|
491
487
|
def _reduce_33( val, _values, result )
|
492
|
-
result =
|
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
|
data/lib/twowaysql/parser.y
CHANGED
@@ -71,7 +71,7 @@ primary : IDENT
|
|
71
71
|
}
|
72
72
|
| SPACES
|
73
73
|
{
|
74
|
-
result =
|
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 =
|
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 =>
|
139
|
+
:debug => false,
|
144
140
|
:preserve_space => true,
|
145
|
-
:preserve_comment =>
|
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
|
163
|
-
BEGIN_END_PATTERN
|
164
|
-
STRING_LITERAL_PATTERN
|
165
|
-
SPLIT_TOKEN_PATTERN
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
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 |
|
183
|
-
s = StringScanner.new(
|
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] ]
|
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 ]
|
data/lib/twowaysql/template.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/twowaysql/version.rb
CHANGED
data/spec/large_sql_spec.rb
CHANGED
@@ -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 "
|
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
|
-
|
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
|