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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e96af138b105ce5c23190556cfe34c20e7d275da
4
- data.tar.gz: 33dc95f6c3d0222cd82b3c2c373c5462c698506f
3
+ metadata.gz: d5571413a37bafba8fb43af7c8ecbf43f5e0638e
4
+ data.tar.gz: d33d23f80b2ad5652c59eb6d12eb6b4cabfda9f0
5
5
  SHA512:
6
- metadata.gz: 8ead60811f2f761ae6da39c124a50dcc3d2cef1eeca80c38a3213fc5d44537ee97276d538996c609b703dd954ceb1bff366bf060e51159505341d51dcbfac707
7
- data.tar.gz: c1eb147f0e416a3f04911f208c23e825cf83530b3d83f392a5dac9382e7cba3d2a868c42c77021a2908ff57f04327152f97861c3de72b482842a6ba507dff3c5
6
+ metadata.gz: 73f76ef17b727d6632a3ab893fad0c222b938e2bee87b92d47bfbdbbfd6e362fe2dfdfcd074ef3112aaf4edf5a9e8e055bdf1f3be05bced91e84c6e46a01de26
7
+ data.tar.gz: eb2275e0b716d9acb7338ed8f6728161f6a32933bf058b6795c2b31c70c28bf6be4f861d7171f0bb459b36c2f4feabffc67a04e10e7f29c3115dcda74d308c4f
@@ -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
@@ -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
@@ -65,10 +65,14 @@ require 'sqlpp/ast'
65
65
  #
66
66
  # op := 'AND' | 'OR' | 'IS' | 'IS NOT'
67
67
  #
68
- # expr2 := expr3
69
- # | expr3 'BETWEEN' expr3 AND expr3
70
- # | expr3 'IN' '(' list ')'
71
- # | expr3 bop expr3
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 (key = _eat(:key, :case))
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
@@ -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)
@@ -1,7 +1,7 @@
1
1
  module SQLPP
2
2
  module Version
3
3
  MAJOR = 1
4
- MINOR = 2
4
+ MINOR = 3
5
5
  TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join(".")
@@ -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
@@ -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.2.0
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-03-15 00:00:00.000000000 Z
11
+ date: 2016-04-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake