sqlpp 1.2.0 → 1.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.
- checksums.yaml +4 -4
- data/lib/sqlpp/ast.rb +7 -1
- data/lib/sqlpp/formatter.rb +13 -1
- data/lib/sqlpp/parser.rb +35 -6
- data/lib/sqlpp/tokenizer.rb +2 -2
- data/lib/sqlpp/version.rb +1 -1
- data/test/formatter_test.rb +25 -0
- data/test/parser_test.rb +35 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d5571413a37bafba8fb43af7c8ecbf43f5e0638e
|
4
|
+
data.tar.gz: d33d23f80b2ad5652c59eb6d12eb6b4cabfda9f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73f76ef17b727d6632a3ab893fad0c222b938e2bee87b92d47bfbdbbfd6e362fe2dfdfcd074ef3112aaf4edf5a9e8e055bdf1f3be05bced91e84c6e46a01de26
|
7
|
+
data.tar.gz: eb2275e0b716d9acb7338ed8f6728161f6a32933bf058b6795c2b31c70c28bf6be4f861d7171f0bb459b36c2f4feabffc67a04e10e7f29c3115dcda74d308c4f
|
data/lib/sqlpp/ast.rb
CHANGED
@@ -3,7 +3,7 @@ module SQLPP
|
|
3
3
|
class Select < Struct.new(:projections, :froms, :wheres, :groups, :orders, :distinct, :limit, :offset)
|
4
4
|
end
|
5
5
|
|
6
|
-
class Expr < Struct.new(:left, :op, :right)
|
6
|
+
class Expr < Struct.new(:left, :op, :right, :not)
|
7
7
|
end
|
8
8
|
|
9
9
|
class Unary < Struct.new(:op, :expr)
|
@@ -32,5 +32,11 @@ module SQLPP
|
|
32
32
|
|
33
33
|
class Offset < Struct.new(:expr)
|
34
34
|
end
|
35
|
+
|
36
|
+
class Subscript < Struct.new(:left, :right)
|
37
|
+
end
|
38
|
+
|
39
|
+
class TypeCast < Struct.new(:value, :type)
|
40
|
+
end
|
35
41
|
end
|
36
42
|
end
|
data/lib/sqlpp/formatter.rb
CHANGED
@@ -85,6 +85,7 @@ module SQLPP
|
|
85
85
|
output << " "
|
86
86
|
end
|
87
87
|
|
88
|
+
output << "NOT " if node.not
|
88
89
|
output << op << " "
|
89
90
|
output << format(node.right)
|
90
91
|
end
|
@@ -164,7 +165,7 @@ module SQLPP
|
|
164
165
|
|
165
166
|
if node.options.any?
|
166
167
|
output << " "
|
167
|
-
output << node.options.map { |opt| opt.upcase }.join("
|
168
|
+
output << node.options.map { |opt| opt.upcase }.join(" ")
|
168
169
|
end
|
169
170
|
|
170
171
|
output
|
@@ -182,6 +183,17 @@ module SQLPP
|
|
182
183
|
string
|
183
184
|
end
|
184
185
|
|
186
|
+
def _format_Subscript(node)
|
187
|
+
output = ""
|
188
|
+
output << format(node.left)
|
189
|
+
output << "[" << format(node.right) << "]"
|
190
|
+
output
|
191
|
+
end
|
192
|
+
|
193
|
+
def _format_TypeCast(node)
|
194
|
+
format(node.value) << '::' << format(node.type)
|
195
|
+
end
|
196
|
+
|
185
197
|
def _indent
|
186
198
|
" " * (@indent || 0)
|
187
199
|
end
|
data/lib/sqlpp/parser.rb
CHANGED
@@ -65,10 +65,14 @@ require 'sqlpp/ast'
|
|
65
65
|
#
|
66
66
|
# op := 'AND' | 'OR' | 'IS' | 'IS NOT'
|
67
67
|
#
|
68
|
-
# expr2 := expr3
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
68
|
+
# expr2 := expr3 optional_op
|
69
|
+
#
|
70
|
+
# optional_op := ''
|
71
|
+
# | 'NOT' optional_op
|
72
|
+
# | 'BETWEEN' expr3 AND expr3
|
73
|
+
# | 'NOT IN' '(' list ')'
|
74
|
+
# | 'IN' '(' list ')'
|
75
|
+
# | bop expr3
|
72
76
|
#
|
73
77
|
# bop := '<' | '<=' | '<>' | '=' | '>=' | '>'
|
74
78
|
#
|
@@ -86,6 +90,8 @@ require 'sqlpp/ast'
|
|
86
90
|
# | id '(' args ')'
|
87
91
|
# | 'CASE' case_stmt 'END'
|
88
92
|
# | '(' expr1 ')'
|
93
|
+
# | expr4 '[' expr1 ']'
|
94
|
+
# | expr4 '::' expr4
|
89
95
|
#
|
90
96
|
# list := expr1
|
91
97
|
# | expr1 ',' list
|
@@ -338,6 +344,9 @@ module SQLPP
|
|
338
344
|
left = _parse_expr3
|
339
345
|
_eat :space
|
340
346
|
|
347
|
+
not_kw = _eat(:key, :not)
|
348
|
+
_eat :space if not_kw
|
349
|
+
|
341
350
|
if (op = _eat(:key, :between))
|
342
351
|
op = op.text
|
343
352
|
|
@@ -368,7 +377,9 @@ module SQLPP
|
|
368
377
|
end
|
369
378
|
|
370
379
|
if right
|
371
|
-
AST::Expr.new(left, op, right)
|
380
|
+
AST::Expr.new(left, op, right, not_kw != nil)
|
381
|
+
elsif not_kw
|
382
|
+
raise UnexpectedToken, "got #{not_kw.inspect}"
|
372
383
|
else
|
373
384
|
left
|
374
385
|
end
|
@@ -385,6 +396,23 @@ module SQLPP
|
|
385
396
|
atom = _parse_atom
|
386
397
|
_eat :space
|
387
398
|
|
399
|
+
if _eat(:punct, "[")
|
400
|
+
subscript = _parse_expr1
|
401
|
+
_eat :space
|
402
|
+
_expect(:punct, "]")
|
403
|
+
_eat :space
|
404
|
+
|
405
|
+
atom = AST::Subscript.new(atom, subscript)
|
406
|
+
end
|
407
|
+
|
408
|
+
if _eat(:punct, "::")
|
409
|
+
_eat :space
|
410
|
+
type = _parse_atom
|
411
|
+
_eat :space
|
412
|
+
|
413
|
+
atom = AST::TypeCast.new(atom, type)
|
414
|
+
end
|
415
|
+
|
388
416
|
if (op = _eat(:punct, /[-+*\/]/))
|
389
417
|
_eat :space
|
390
418
|
AST::Expr.new(atom, op.text, _parse_expr3)
|
@@ -398,7 +426,7 @@ module SQLPP
|
|
398
426
|
if (lit = _eat(:lit))
|
399
427
|
AST::Atom.new(:lit, lit.text)
|
400
428
|
|
401
|
-
elsif
|
429
|
+
elsif _eat(:key, :case)
|
402
430
|
_parse_case
|
403
431
|
|
404
432
|
elsif _eat(:punct, "(")
|
@@ -470,6 +498,7 @@ module SQLPP
|
|
470
498
|
def _parse_list
|
471
499
|
_eat :space
|
472
500
|
args = []
|
501
|
+
return args if _peek(:punct, ')')
|
473
502
|
|
474
503
|
loop do
|
475
504
|
args << _parse_expr1
|
data/lib/sqlpp/tokenizer.rb
CHANGED
@@ -85,9 +85,9 @@ module SQLPP
|
|
85
85
|
Token.new(:lit, num, pos)
|
86
86
|
elsif (id = @scanner.scan(/\w+/))
|
87
87
|
Token.new(:id, id, pos)
|
88
|
-
elsif (punct = @scanner.scan(
|
88
|
+
elsif (punct = @scanner.scan(/<=|<>|!=|>=|::/))
|
89
89
|
Token.new(:punct, punct, pos)
|
90
|
-
elsif (punct = @scanner.scan(/[<>=\(\)
|
90
|
+
elsif (punct = @scanner.scan(/[<>=\(\).*,\/+\-\[\]]/))
|
91
91
|
Token.new(:punct, punct, pos)
|
92
92
|
elsif (delim = @scanner.scan(/["`]/))
|
93
93
|
contents = _scan_to_delim(delim, pos)
|
data/lib/sqlpp/version.rb
CHANGED
data/test/formatter_test.rb
CHANGED
@@ -85,6 +85,31 @@ LIMIT 10 OFFSET 5
|
|
85
85
|
SQL
|
86
86
|
end
|
87
87
|
|
88
|
+
def test_format_NOT_expr
|
89
|
+
ast = _parser("select * from foo where x not in (5, 6)").parse
|
90
|
+
assert_equal <<-SQL, _format(ast)
|
91
|
+
SELECT *
|
92
|
+
FROM foo
|
93
|
+
WHERE x NOT IN (5, 6)
|
94
|
+
SQL
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_format_subscript_in_expr
|
98
|
+
ast = _parser("select (array_agg(x))[0] from foo").parse
|
99
|
+
assert_equal <<-SQL, _format(ast)
|
100
|
+
SELECT (array_agg(x))[0]
|
101
|
+
FROM foo
|
102
|
+
SQL
|
103
|
+
end
|
104
|
+
|
105
|
+
def test_format_double_colon_typecast
|
106
|
+
ast = _parser("select 'month'::interval from foo").parse
|
107
|
+
assert_equal <<-SQL, _format(ast)
|
108
|
+
SELECT 'month'::interval
|
109
|
+
FROM foo
|
110
|
+
SQL
|
111
|
+
end
|
112
|
+
|
88
113
|
def _parser(string)
|
89
114
|
SQLPP::Parser.new(string)
|
90
115
|
end
|
data/test/parser_test.rb
CHANGED
@@ -309,6 +309,41 @@ class ParserTest < Minitest::Test
|
|
309
309
|
assert_equal "5", s.offset.expr.left
|
310
310
|
end
|
311
311
|
|
312
|
+
def test_accepts_not_in_syntax
|
313
|
+
s = _parser("select * from x where x.id not in (5)").parse_select
|
314
|
+
assert s.wheres.not
|
315
|
+
end
|
316
|
+
|
317
|
+
def test_accepts_array_subscript_in_expression
|
318
|
+
expr = _parser("a[5]").parse_expression
|
319
|
+
assert_instance_of SQLPP::AST::Subscript, expr
|
320
|
+
assert_instance_of SQLPP::AST::Atom, expr.left
|
321
|
+
assert_instance_of SQLPP::AST::Atom, expr.right
|
322
|
+
assert_equal :attr, expr.left.type
|
323
|
+
assert_equal "a", expr.left.left
|
324
|
+
assert_equal :lit, expr.right.type
|
325
|
+
assert_equal "5", expr.right.left
|
326
|
+
end
|
327
|
+
|
328
|
+
def test_accepts_double_colon_as_typecast
|
329
|
+
expr = _parser("'month'::INTERVAL").parse_expression
|
330
|
+
assert_instance_of SQLPP::AST::TypeCast, expr
|
331
|
+
assert_instance_of SQLPP::AST::Atom, expr.value
|
332
|
+
assert_instance_of SQLPP::AST::Atom, expr.type
|
333
|
+
assert_equal :lit, expr.value.type
|
334
|
+
assert_equal "'month'", expr.value.left
|
335
|
+
assert_equal :attr, expr.type.type
|
336
|
+
assert_equal "INTERVAL", expr.type.left
|
337
|
+
end
|
338
|
+
|
339
|
+
def test_accept_empty_parameter_list
|
340
|
+
expr = _parser("NOW()").parse_expression
|
341
|
+
assert_instance_of SQLPP::AST::Atom, expr
|
342
|
+
assert_equal :func, expr.type
|
343
|
+
assert_equal "NOW", expr.left
|
344
|
+
assert_equal 0, expr.right.count
|
345
|
+
end
|
346
|
+
|
312
347
|
def _parser(string)
|
313
348
|
SQLPP::Parser.new(string)
|
314
349
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sqlpp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jamis Buck
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|