rgviz 0.14 → 0.15
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/spec/rgviz/lexer_spec.rb +171 -0
- data/spec/rgviz/parser_spec.rb +360 -0
- metadata +5 -3
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'rgviz'
|
2
|
+
|
3
|
+
include Rgviz
|
4
|
+
|
5
|
+
describe Lexer do
|
6
|
+
def self.it_lexes_keyword(str, token_value)
|
7
|
+
it "lexes #{str}" do
|
8
|
+
lex = Lexer.new str
|
9
|
+
tok = lex.next_token
|
10
|
+
tok.value.should == token_value
|
11
|
+
end
|
12
|
+
|
13
|
+
it "lexes #{str} upcase" do
|
14
|
+
lex = Lexer.new str.upcase
|
15
|
+
tok = lex.next_token
|
16
|
+
tok.value.should == token_value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.it_lexes_id(str, id = str)
|
21
|
+
it "lexes identifier #{str}" do
|
22
|
+
lex = Lexer.new str
|
23
|
+
tok = lex.next_token
|
24
|
+
tok.value.should == Token::ID
|
25
|
+
tok.string.should == id
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.it_lexes_string(str, id = str)
|
30
|
+
it "lexes string #{str}" do
|
31
|
+
lex = Lexer.new str
|
32
|
+
tok = lex.next_token
|
33
|
+
tok.value.should == Token::STRING
|
34
|
+
tok.string.should == id
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.it_lexes_token(str, token_value)
|
39
|
+
it "lexes #{str}" do
|
40
|
+
lex = Lexer.new str
|
41
|
+
tok = lex.next_token
|
42
|
+
tok.value.should == token_value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.it_lexes_integer(str, number)
|
47
|
+
it "lexes #{str}" do
|
48
|
+
lex = Lexer.new str
|
49
|
+
tok = lex.next_token
|
50
|
+
tok.value.should == Token::INTEGER
|
51
|
+
tok.number.should == number
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.it_lexes_decimal(str, number)
|
56
|
+
it "lexes #{str}" do
|
57
|
+
lex = Lexer.new str
|
58
|
+
tok = lex.next_token
|
59
|
+
tok.value.should == Token::DECIMAL
|
60
|
+
tok.number.should == number
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.it_lexes_eof(str)
|
65
|
+
it "lexes eof #{str}" do
|
66
|
+
lex = Lexer.new str
|
67
|
+
tok = lex.next_token
|
68
|
+
tok.value.should == Token::EOF
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.it_lexes_error(str)
|
73
|
+
it "lexes error #{str}" do
|
74
|
+
lex = Lexer.new "x#{str}"
|
75
|
+
tok = lex.next_token
|
76
|
+
tok.value.should == Token::ID
|
77
|
+
tok.string.should == 'x'
|
78
|
+
lambda { lex.next_token }.should raise_error(ParseException)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it_lexes_keyword 'and', Token::And
|
83
|
+
it_lexes_keyword 'asc', Token::Asc
|
84
|
+
it_lexes_keyword 'avg', Token::Avg
|
85
|
+
it_lexes_keyword 'by', Token::By
|
86
|
+
it_lexes_keyword 'contains', Token::Contains
|
87
|
+
it_lexes_keyword 'count', Token::Count
|
88
|
+
it_lexes_keyword 'date', Token::Date
|
89
|
+
it_lexes_keyword 'datediff', Token::DateDiff
|
90
|
+
it_lexes_keyword 'datetime', Token::DateTime
|
91
|
+
it_lexes_keyword 'day', Token::Day
|
92
|
+
it_lexes_keyword 'dayofweek', Token::DayOfWeek
|
93
|
+
it_lexes_keyword 'desc', Token::Desc
|
94
|
+
it_lexes_keyword 'ends', Token::Ends
|
95
|
+
it_lexes_keyword 'false', Token::False
|
96
|
+
it_lexes_keyword 'format', Token::Format
|
97
|
+
it_lexes_keyword 'group', Token::Group
|
98
|
+
it_lexes_keyword 'hour', Token::Hour
|
99
|
+
it_lexes_keyword 'is', Token::Is
|
100
|
+
it_lexes_keyword 'label', Token::Label
|
101
|
+
it_lexes_keyword 'like', Token::Like
|
102
|
+
it_lexes_keyword 'limit', Token::Limit
|
103
|
+
it_lexes_keyword 'lower', Token::Lower
|
104
|
+
it_lexes_keyword 'matches', Token::Matches
|
105
|
+
it_lexes_keyword 'millisecond', Token::Millisecond
|
106
|
+
it_lexes_keyword 'min', Token::Min
|
107
|
+
it_lexes_keyword 'minute', Token::Minute
|
108
|
+
it_lexes_keyword 'max', Token::Max
|
109
|
+
it_lexes_keyword 'month', Token::Month
|
110
|
+
it_lexes_keyword 'not', Token::Not
|
111
|
+
it_lexes_keyword 'now', Token::Now
|
112
|
+
it_lexes_keyword 'no_format', Token::NoFormat
|
113
|
+
it_lexes_keyword 'no_values', Token::NoValues
|
114
|
+
it_lexes_keyword 'null', Token::Null
|
115
|
+
it_lexes_keyword 'offset', Token::Offset
|
116
|
+
it_lexes_keyword 'options', Token::Options
|
117
|
+
it_lexes_keyword 'or', Token::Or
|
118
|
+
it_lexes_keyword 'order', Token::Order
|
119
|
+
it_lexes_keyword 'pivot', Token::Pivot
|
120
|
+
it_lexes_keyword 'quarter', Token::Quarter
|
121
|
+
it_lexes_keyword 'second', Token::Second
|
122
|
+
it_lexes_keyword 'select', Token::Select
|
123
|
+
it_lexes_keyword 'starts', Token::Starts
|
124
|
+
it_lexes_keyword 'sum', Token::Sum
|
125
|
+
it_lexes_keyword 'timeofday', Token::TimeOfDay
|
126
|
+
it_lexes_keyword 'timestamp', Token::Timestamp
|
127
|
+
it_lexes_keyword 'todate', Token::ToDate
|
128
|
+
it_lexes_keyword 'true', Token::True
|
129
|
+
it_lexes_keyword 'upper', Token::Upper
|
130
|
+
it_lexes_keyword 'where', Token::Where
|
131
|
+
it_lexes_keyword 'with', Token::With
|
132
|
+
it_lexes_keyword 'year', Token::Year
|
133
|
+
|
134
|
+
it_lexes_id 'selected'
|
135
|
+
it_lexes_id ' selected ', 'selected'
|
136
|
+
it_lexes_id '`selected`', 'selected'
|
137
|
+
it_lexes_id '`some string`', 'some string'
|
138
|
+
it_lexes_id 'hello123bye'
|
139
|
+
it_lexes_id 'hello_123_bye'
|
140
|
+
it_lexes_string "'hello world'", "hello world"
|
141
|
+
it_lexes_string '"hello world"', "hello world"
|
142
|
+
|
143
|
+
it_lexes_token '+', Token::PLUS
|
144
|
+
it_lexes_token '-', Token::MINUS
|
145
|
+
it_lexes_token '*', Token::STAR
|
146
|
+
it_lexes_token '/', Token::SLASH
|
147
|
+
|
148
|
+
it_lexes_token ',', Token::COMMA
|
149
|
+
it_lexes_token '(', Token::LPAREN
|
150
|
+
it_lexes_token ')', Token::RPAREN
|
151
|
+
it_lexes_token '=', Token::EQ
|
152
|
+
it_lexes_token '<', Token::LT
|
153
|
+
it_lexes_token '<=', Token::LTE
|
154
|
+
it_lexes_token '>', Token::GT
|
155
|
+
it_lexes_token '>=', Token::GTE
|
156
|
+
it_lexes_token '!=', Token::NEQ
|
157
|
+
it_lexes_token '<>', Token::NEQ
|
158
|
+
|
159
|
+
it_lexes_integer '1', 1
|
160
|
+
it_lexes_integer '0123', 123
|
161
|
+
it_lexes_integer '45678791230', 45678791230
|
162
|
+
it_lexes_decimal '123.456', 123.456
|
163
|
+
it_lexes_decimal '.456', 0.456
|
164
|
+
|
165
|
+
it_lexes_eof ''
|
166
|
+
it_lexes_eof " \t\n\r"
|
167
|
+
|
168
|
+
it_lexes_error '!'
|
169
|
+
it_lexes_error '?'
|
170
|
+
it_lexes_error ':'
|
171
|
+
end
|
@@ -0,0 +1,360 @@
|
|
1
|
+
require 'rgviz'
|
2
|
+
|
3
|
+
include Rgviz
|
4
|
+
|
5
|
+
describe Parser do
|
6
|
+
def parse(string)
|
7
|
+
Parser.new(string).parse
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse_select_single_column(string)
|
11
|
+
query = parse "select #{string}"
|
12
|
+
select = query.select
|
13
|
+
select.columns.length.should == 1
|
14
|
+
|
15
|
+
select.columns[0]
|
16
|
+
end
|
17
|
+
|
18
|
+
def parse_where(string)
|
19
|
+
query = parse "where #{string}"
|
20
|
+
query.where.expression
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.it_parses_as_identifier(str)
|
24
|
+
it "parses #{str} as identifier" do
|
25
|
+
col = parse_select_single_column "#{str}"
|
26
|
+
col.should be_a_kind_of IdColumn
|
27
|
+
col.name.should == "#{str}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.it_parses_columns_container(str, method)
|
32
|
+
it "parses #{str}" do
|
33
|
+
query = parse "#{str} foo"
|
34
|
+
cols = query.send method
|
35
|
+
cols.columns.length == 1
|
36
|
+
cols.columns[0].should be_a_kind_of IdColumn
|
37
|
+
cols.columns[0].name.should == 'foo'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.it_raises_on(str)
|
42
|
+
it "raises on #{str}" do
|
43
|
+
lambda { parse "#{str}" }.should raise_error(ParseException)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "parses empty" do
|
48
|
+
query = parse ''
|
49
|
+
query.select.should be_nil
|
50
|
+
end
|
51
|
+
|
52
|
+
it "parses select all" do
|
53
|
+
query = parse 'select *'
|
54
|
+
select = query.select
|
55
|
+
select.columns.should be_empty
|
56
|
+
end
|
57
|
+
|
58
|
+
it "parses select simple columns" do
|
59
|
+
query = parse 'select one, two, three'
|
60
|
+
select = query.select
|
61
|
+
|
62
|
+
select.columns.length.should == 3
|
63
|
+
|
64
|
+
['one', 'two', 'three'].each_with_index do |name, i|
|
65
|
+
select.columns[i].should be_a_kind_of IdColumn
|
66
|
+
select.columns[i].name.should == name
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it "parses select number" do
|
71
|
+
col = parse_select_single_column '1'
|
72
|
+
col.should be_a_kind_of NumberColumn
|
73
|
+
col.value.should == 1
|
74
|
+
end
|
75
|
+
|
76
|
+
it "parses select number with minus" do
|
77
|
+
col = parse_select_single_column '-1'
|
78
|
+
col.should be_a_kind_of NumberColumn
|
79
|
+
col.value.should == -1
|
80
|
+
end
|
81
|
+
|
82
|
+
it "parses select number with plus" do
|
83
|
+
col = parse_select_single_column '+1'
|
84
|
+
col.should be_a_kind_of NumberColumn
|
85
|
+
col.value.should == 1
|
86
|
+
end
|
87
|
+
|
88
|
+
it "parses select parenthesized number" do
|
89
|
+
col = parse_select_single_column '(1)'
|
90
|
+
col.should be_a_kind_of NumberColumn
|
91
|
+
col.value.should == 1
|
92
|
+
end
|
93
|
+
|
94
|
+
it "parses select string" do
|
95
|
+
col = parse_select_single_column '"hello"'
|
96
|
+
col.should be_a_kind_of StringColumn
|
97
|
+
col.value.should == 'hello'
|
98
|
+
end
|
99
|
+
|
100
|
+
it "parses select false" do
|
101
|
+
col = parse_select_single_column 'false'
|
102
|
+
col.should be_a_kind_of BooleanColumn
|
103
|
+
col.value.should == false
|
104
|
+
end
|
105
|
+
|
106
|
+
it "parses select true" do
|
107
|
+
col = parse_select_single_column 'true'
|
108
|
+
col.should be_a_kind_of BooleanColumn
|
109
|
+
col.value.should == true
|
110
|
+
end
|
111
|
+
|
112
|
+
it "parses select date" do
|
113
|
+
col = parse_select_single_column 'date "2010-01-02"'
|
114
|
+
col.should be_a_kind_of DateColumn
|
115
|
+
col.value.should == Date.parse('2010-01-02')
|
116
|
+
end
|
117
|
+
|
118
|
+
it "parses select timeofday" do
|
119
|
+
col = parse_select_single_column 'timeofday "12:01:02"'
|
120
|
+
col.should be_a_kind_of TimeOfDayColumn
|
121
|
+
col.value.hour.should == 12
|
122
|
+
col.value.min.should == 1
|
123
|
+
col.value.sec.should == 2
|
124
|
+
end
|
125
|
+
|
126
|
+
it "parses select datetime" do
|
127
|
+
col = parse_select_single_column 'datetime "2010-01-02 12:02:03"'
|
128
|
+
col.should be_a_kind_of DateTimeColumn
|
129
|
+
col.value.should == Time.parse('2010-01-02 12:02:03')
|
130
|
+
end
|
131
|
+
|
132
|
+
[
|
133
|
+
['*', ScalarFunctionColumn::Product],
|
134
|
+
['/', ScalarFunctionColumn::Quotient],
|
135
|
+
['+', ScalarFunctionColumn::Sum],
|
136
|
+
['-', ScalarFunctionColumn::Difference]
|
137
|
+
].each do |str, func|
|
138
|
+
it "parses select #{func}" do
|
139
|
+
col = parse_select_single_column "1 #{str} one"
|
140
|
+
col.should be_a_kind_of ScalarFunctionColumn
|
141
|
+
col.function.should == func
|
142
|
+
|
143
|
+
args = col.arguments
|
144
|
+
args.length.should == 2
|
145
|
+
|
146
|
+
args[0].should be_a_kind_of NumberColumn
|
147
|
+
args[0].value.should == 1
|
148
|
+
|
149
|
+
args[1].should be_a_kind_of IdColumn
|
150
|
+
args[1].name.should == "one"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
it "parses compound arithmetic" do
|
155
|
+
col = parse_select_single_column "1 * 2 + 3 * 4"
|
156
|
+
col.should be_kind_of ScalarFunctionColumn
|
157
|
+
col.function.should == ScalarFunctionColumn::Sum
|
158
|
+
|
159
|
+
col.arguments.length.should == 2
|
160
|
+
|
161
|
+
[0, 1].each do |i|
|
162
|
+
sub = col.arguments[i]
|
163
|
+
sub.should be_kind_of ScalarFunctionColumn
|
164
|
+
sub.function.should == ScalarFunctionColumn::Product
|
165
|
+
sub.arguments.length.should == 2
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
[
|
170
|
+
['min', AggregateColumn::Min],
|
171
|
+
['max', AggregateColumn::Max],
|
172
|
+
['count', AggregateColumn::Count],
|
173
|
+
['avg', AggregateColumn::Avg],
|
174
|
+
['sum', AggregateColumn::Sum]
|
175
|
+
].each do |str, function|
|
176
|
+
it "parses #{str} aggregation" do
|
177
|
+
col = parse_select_single_column "#{str}(col)"
|
178
|
+
col.should be_a_kind_of AggregateColumn
|
179
|
+
col.function.should == function
|
180
|
+
|
181
|
+
col.argument.should be_a_kind_of IdColumn
|
182
|
+
col.argument.name.should == 'col'
|
183
|
+
end
|
184
|
+
|
185
|
+
it_parses_as_identifier str
|
186
|
+
end
|
187
|
+
|
188
|
+
[
|
189
|
+
['year', ScalarFunctionColumn::Year],
|
190
|
+
['month', ScalarFunctionColumn::Month],
|
191
|
+
['day', ScalarFunctionColumn::Day],
|
192
|
+
['hour', ScalarFunctionColumn::Hour],
|
193
|
+
['minute', ScalarFunctionColumn::Minute],
|
194
|
+
['second', ScalarFunctionColumn::Second],
|
195
|
+
['millisecond', ScalarFunctionColumn::Millisecond],
|
196
|
+
['now', ScalarFunctionColumn::Now],
|
197
|
+
['datediff', ScalarFunctionColumn::DateDiff],
|
198
|
+
['lower', ScalarFunctionColumn::Lower],
|
199
|
+
['upper', ScalarFunctionColumn::Upper],
|
200
|
+
['quarter', ScalarFunctionColumn::Quarter],
|
201
|
+
['dayofweek', ScalarFunctionColumn::DayOfWeek],
|
202
|
+
['todate', ScalarFunctionColumn::ToDate]
|
203
|
+
].each do |str, function|
|
204
|
+
it "parses #{str} function" do
|
205
|
+
col = parse_select_single_column "#{str}(col)"
|
206
|
+
col.should be_a_kind_of ScalarFunctionColumn
|
207
|
+
col.function.should == function
|
208
|
+
|
209
|
+
col.arguments.length.should == 1
|
210
|
+
col.arguments[0].should be_a_kind_of IdColumn
|
211
|
+
col.arguments[0].name.should == 'col'
|
212
|
+
end
|
213
|
+
|
214
|
+
it_parses_as_identifier str
|
215
|
+
end
|
216
|
+
|
217
|
+
it "parses datediff function with many arguments" do
|
218
|
+
col = parse_select_single_column "datediff(1, 2)"
|
219
|
+
col.should be_a_kind_of ScalarFunctionColumn
|
220
|
+
col.function.should == ScalarFunctionColumn::DateDiff
|
221
|
+
|
222
|
+
col.arguments.length.should == 2
|
223
|
+
col.arguments[0].value == 1
|
224
|
+
col.arguments[1].value == 2
|
225
|
+
end
|
226
|
+
|
227
|
+
[
|
228
|
+
['=', BinaryExpression::Eq],
|
229
|
+
['!=', BinaryExpression::Neq],
|
230
|
+
['<>', BinaryExpression::Neq],
|
231
|
+
['<', BinaryExpression::Lt],
|
232
|
+
['<=', BinaryExpression::Lte],
|
233
|
+
['>', BinaryExpression::Gt],
|
234
|
+
['>=', BinaryExpression::Gte],
|
235
|
+
['contains', BinaryExpression::Contains],
|
236
|
+
['starts with', BinaryExpression::StartsWith],
|
237
|
+
['ends with', BinaryExpression::EndsWith],
|
238
|
+
['matches', BinaryExpression::Matches],
|
239
|
+
['like', BinaryExpression::Like]
|
240
|
+
].each do |str, operator|
|
241
|
+
it "parses where #{str} 1" do
|
242
|
+
exp = parse_where "col #{str} 1"
|
243
|
+
exp.should be_a_kind_of BinaryExpression
|
244
|
+
exp.operator.should == operator
|
245
|
+
exp.left.should be_a_kind_of IdColumn
|
246
|
+
exp.left.name.should == 'col'
|
247
|
+
exp.right.should be_a_kind_of NumberColumn
|
248
|
+
exp.right.value.should == 1
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
it_parses_as_identifier 'contains'
|
253
|
+
it_parses_as_identifier 'starts'
|
254
|
+
it_parses_as_identifier 'ends'
|
255
|
+
it_parses_as_identifier 'with'
|
256
|
+
it_parses_as_identifier 'matches'
|
257
|
+
it_parses_as_identifier 'like'
|
258
|
+
it_parses_as_identifier 'no_values'
|
259
|
+
it_parses_as_identifier 'no_format'
|
260
|
+
it_parses_as_identifier 'is'
|
261
|
+
it_parses_as_identifier 'null'
|
262
|
+
|
263
|
+
it_parses_columns_container 'group by', :group_by
|
264
|
+
it_parses_columns_container 'pivot', :pivot
|
265
|
+
|
266
|
+
[
|
267
|
+
['', Sort::Asc],
|
268
|
+
[' asc', Sort::Asc],
|
269
|
+
[' desc', Sort::Desc]
|
270
|
+
].each do |str, order|
|
271
|
+
it "parses order by" do
|
272
|
+
query = parse "order by foo #{order}, bar #{order}"
|
273
|
+
order_by = query.order_by
|
274
|
+
|
275
|
+
sorts = order_by.sorts
|
276
|
+
|
277
|
+
sorts.length.should == 2
|
278
|
+
|
279
|
+
sorts[0].column.should be_a_kind_of IdColumn
|
280
|
+
sorts[0].column.name.should == 'foo'
|
281
|
+
sorts[0].order.should == order
|
282
|
+
|
283
|
+
sorts[1].column.should be_a_kind_of IdColumn
|
284
|
+
sorts[1].column.name.should == 'bar'
|
285
|
+
sorts[1].order.should == order
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
it "parses limit" do
|
290
|
+
query = parse "limit 10"
|
291
|
+
query.limit.should == 10
|
292
|
+
end
|
293
|
+
|
294
|
+
it "parses offset" do
|
295
|
+
query = parse "offset 10"
|
296
|
+
query.offset.should == 10
|
297
|
+
end
|
298
|
+
|
299
|
+
it "parses label" do
|
300
|
+
query = parse "label one 'unu', two 'du'"
|
301
|
+
labels = query.labels
|
302
|
+
labels.length.should == 2
|
303
|
+
|
304
|
+
labels[0].column.should be_a_kind_of IdColumn
|
305
|
+
labels[0].column.name.should == 'one'
|
306
|
+
labels[0].label.should == 'unu'
|
307
|
+
|
308
|
+
labels[1].column.should be_a_kind_of IdColumn
|
309
|
+
labels[1].column.name.should == 'two'
|
310
|
+
labels[1].label.should == 'du'
|
311
|
+
end
|
312
|
+
|
313
|
+
it "parses format" do
|
314
|
+
query = parse "format one 'unu', two 'du'"
|
315
|
+
formats = query.formats
|
316
|
+
formats.length.should == 2
|
317
|
+
|
318
|
+
formats[0].column.should be_a_kind_of IdColumn
|
319
|
+
formats[0].column.name.should == 'one'
|
320
|
+
formats[0].pattern.should == 'unu'
|
321
|
+
|
322
|
+
formats[1].column.should be_a_kind_of IdColumn
|
323
|
+
formats[1].column.name.should == 'two'
|
324
|
+
formats[1].pattern.should == 'du'
|
325
|
+
end
|
326
|
+
|
327
|
+
it "parses options" do
|
328
|
+
query = parse "options no_values no_format"
|
329
|
+
options = query.options
|
330
|
+
options.length.should == 2
|
331
|
+
|
332
|
+
options[0].should be_a_kind_of Option
|
333
|
+
options[0].option.should == Option::NoValues
|
334
|
+
|
335
|
+
options[1].should be_a_kind_of Option
|
336
|
+
options[1].option.should == Option::NoFormat
|
337
|
+
end
|
338
|
+
|
339
|
+
it_raises_on 'select'
|
340
|
+
it_raises_on 'where'
|
341
|
+
it_raises_on 'where 1'
|
342
|
+
it_raises_on 'where 1 <'
|
343
|
+
it_raises_on 'group by'
|
344
|
+
it_raises_on 'group by foo bar'
|
345
|
+
it_raises_on 'pivot'
|
346
|
+
it_raises_on 'order by'
|
347
|
+
it_raises_on 'order by foo bar'
|
348
|
+
it_raises_on 'limit'
|
349
|
+
it_raises_on 'limit foo'
|
350
|
+
it_raises_on 'offset'
|
351
|
+
it_raises_on 'offset foo'
|
352
|
+
it_raises_on 'label'
|
353
|
+
it_raises_on 'label foo'
|
354
|
+
it_raises_on 'label `foo`'
|
355
|
+
it_raises_on 'format'
|
356
|
+
it_raises_on 'format foo'
|
357
|
+
it_raises_on 'format `foo`'
|
358
|
+
it_raises_on 'options'
|
359
|
+
it_raises_on 'options foobar'
|
360
|
+
end
|
metadata
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rgviz
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: "0.
|
8
|
+
- 15
|
9
|
+
version: "0.15"
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Ary Borenszweig
|
@@ -34,6 +34,8 @@ files:
|
|
34
34
|
- lib/rgviz/token.rb
|
35
35
|
- lib/rgviz/visitor.rb
|
36
36
|
- lib/rgviz/table.rb
|
37
|
+
- spec/rgviz/lexer_spec.rb
|
38
|
+
- spec/rgviz/parser_spec.rb
|
37
39
|
has_rdoc: true
|
38
40
|
homepage: http://code.google.com/p/rgviz
|
39
41
|
licenses: []
|