ronin-sql 0.2.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. data/.document +4 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +1 -0
  4. data/.yardopts +1 -0
  5. data/COPYING.txt +623 -288
  6. data/{History.txt → ChangeLog.md} +33 -35
  7. data/Gemfile +25 -0
  8. data/README.md +110 -0
  9. data/Rakefile +30 -20
  10. data/bin/ronin-sql +18 -5
  11. data/gemspec.yml +16 -0
  12. data/lib/ronin/formatting/extensions/sql.rb +4 -3
  13. data/lib/ronin/formatting/extensions/sql/string.rb +83 -10
  14. data/lib/ronin/formatting/sql.rb +4 -3
  15. data/lib/ronin/sql.rb +5 -12
  16. data/lib/ronin/{code/sql/create_index.rb → sql/binary_expr.rb} +25 -18
  17. data/lib/ronin/sql/clause.rb +72 -0
  18. data/lib/ronin/sql/clauses.rb +297 -0
  19. data/lib/ronin/sql/emittable.rb +84 -0
  20. data/lib/ronin/sql/emitter.rb +375 -0
  21. data/lib/ronin/sql/field.rb +106 -0
  22. data/lib/ronin/{code/sql/as.rb → sql/fields.rb} +36 -17
  23. data/lib/ronin/{code/sql/binary_expr.rb → sql/function.rb} +27 -27
  24. data/lib/ronin/sql/functions.rb +989 -0
  25. data/lib/ronin/sql/injection.rb +125 -157
  26. data/lib/ronin/{code/sql/default_values_clause.rb → sql/literal.rb} +13 -11
  27. data/lib/ronin/sql/literals.rb +72 -0
  28. data/lib/ronin/sql/operators.rb +332 -0
  29. data/lib/ronin/sql/sql.rb +86 -0
  30. data/lib/ronin/sql/statement.rb +70 -0
  31. data/lib/ronin/sql/statement_list.rb +110 -0
  32. data/lib/ronin/sql/statements.rb +115 -0
  33. data/lib/ronin/{code/sql/desc.rb → sql/unary_expr.rb} +11 -11
  34. data/lib/ronin/sql/version.rb +5 -4
  35. data/ronin-sql.gemspec +61 -0
  36. data/spec/formatting/sql/string_spec.rb +172 -0
  37. data/spec/spec_helper.rb +1 -4
  38. data/spec/sql/binary_expr.rb +5 -0
  39. data/spec/sql/binary_expr_examples.rb +25 -0
  40. data/spec/sql/clause_examples.rb +43 -0
  41. data/spec/sql/clause_spec.rb +31 -0
  42. data/spec/sql/clauses_spec.rb +43 -0
  43. data/spec/sql/emittable_spec.rb +41 -0
  44. data/spec/sql/emitter_spec.rb +472 -0
  45. data/spec/sql/field_spec.rb +103 -0
  46. data/spec/sql/fields_spec.rb +40 -0
  47. data/spec/sql/function_examples.rb +30 -0
  48. data/spec/sql/function_spec.rb +25 -0
  49. data/spec/sql/functions_spec.rb +110 -0
  50. data/spec/sql/injection_spec.rb +233 -0
  51. data/spec/sql/literal_spec.rb +5 -0
  52. data/spec/sql/literals_spec.rb +46 -0
  53. data/spec/sql/operators_spec.rb +44 -0
  54. data/spec/sql/sql_spec.rb +18 -0
  55. data/spec/sql/statement_examples.rb +39 -0
  56. data/spec/sql/statement_list_spec.rb +48 -0
  57. data/spec/sql/statement_sql.rb +38 -0
  58. data/spec/sql/statements_spec.rb +22 -0
  59. data/spec/sql/unary_expr.rb +5 -0
  60. data/spec/sql/unary_expr_examples.rb +20 -0
  61. metadata +116 -217
  62. data.tar.gz.sig +0 -0
  63. data/Manifest.txt +0 -108
  64. data/README.txt +0 -112
  65. data/lib/ronin/code/sql.rb +0 -22
  66. data/lib/ronin/code/sql/add_column_clause.rb +0 -42
  67. data/lib/ronin/code/sql/alter_table.rb +0 -52
  68. data/lib/ronin/code/sql/asc.rb +0 -36
  69. data/lib/ronin/code/sql/between.rb +0 -66
  70. data/lib/ronin/code/sql/clause.rb +0 -35
  71. data/lib/ronin/code/sql/code.rb +0 -35
  72. data/lib/ronin/code/sql/common_dialect.rb +0 -66
  73. data/lib/ronin/code/sql/create.rb +0 -74
  74. data/lib/ronin/code/sql/create_table.rb +0 -44
  75. data/lib/ronin/code/sql/create_view.rb +0 -41
  76. data/lib/ronin/code/sql/delete.rb +0 -52
  77. data/lib/ronin/code/sql/dialect.rb +0 -282
  78. data/lib/ronin/code/sql/drop.rb +0 -55
  79. data/lib/ronin/code/sql/drop_index.rb +0 -41
  80. data/lib/ronin/code/sql/drop_table.rb +0 -41
  81. data/lib/ronin/code/sql/drop_view.rb +0 -41
  82. data/lib/ronin/code/sql/emittable.rb +0 -100
  83. data/lib/ronin/code/sql/exceptions.rb +0 -24
  84. data/lib/ronin/code/sql/exceptions/unknown_clause.rb +0 -29
  85. data/lib/ronin/code/sql/exceptions/unknown_dialect.rb +0 -29
  86. data/lib/ronin/code/sql/exceptions/unknown_statement.rb +0 -29
  87. data/lib/ronin/code/sql/expr.rb +0 -102
  88. data/lib/ronin/code/sql/field.rb +0 -101
  89. data/lib/ronin/code/sql/fields_clause.rb +0 -46
  90. data/lib/ronin/code/sql/from_clause.rb +0 -42
  91. data/lib/ronin/code/sql/function.rb +0 -53
  92. data/lib/ronin/code/sql/group_by_clause.rb +0 -46
  93. data/lib/ronin/code/sql/having_clause.rb +0 -46
  94. data/lib/ronin/code/sql/in.rb +0 -47
  95. data/lib/ronin/code/sql/injected_statement.rb +0 -100
  96. data/lib/ronin/code/sql/injection.rb +0 -203
  97. data/lib/ronin/code/sql/insert.rb +0 -54
  98. data/lib/ronin/code/sql/intersect_clause.rb +0 -42
  99. data/lib/ronin/code/sql/join_clause.rb +0 -123
  100. data/lib/ronin/code/sql/like.rb +0 -73
  101. data/lib/ronin/code/sql/limit_clause.rb +0 -42
  102. data/lib/ronin/code/sql/modifier.rb +0 -48
  103. data/lib/ronin/code/sql/offset_clause.rb +0 -42
  104. data/lib/ronin/code/sql/on_clause.rb +0 -55
  105. data/lib/ronin/code/sql/order_by_clause.rb +0 -42
  106. data/lib/ronin/code/sql/program.rb +0 -225
  107. data/lib/ronin/code/sql/rename_to_clause.rb +0 -42
  108. data/lib/ronin/code/sql/replace.rb +0 -54
  109. data/lib/ronin/code/sql/select.rb +0 -103
  110. data/lib/ronin/code/sql/set_clause.rb +0 -42
  111. data/lib/ronin/code/sql/statement.rb +0 -180
  112. data/lib/ronin/code/sql/token.rb +0 -62
  113. data/lib/ronin/code/sql/unary_expr.rb +0 -47
  114. data/lib/ronin/code/sql/union_all_clause.rb +0 -42
  115. data/lib/ronin/code/sql/union_clause.rb +0 -42
  116. data/lib/ronin/code/sql/update.rb +0 -52
  117. data/lib/ronin/code/sql/values_clause.rb +0 -46
  118. data/lib/ronin/code/sql/where_clause.rb +0 -42
  119. data/lib/ronin/sql/error.rb +0 -26
  120. data/lib/ronin/sql/error/error.rb +0 -62
  121. data/lib/ronin/sql/error/extensions.rb +0 -22
  122. data/lib/ronin/sql/error/extensions/string.rb +0 -77
  123. data/lib/ronin/sql/error/message.rb +0 -62
  124. data/lib/ronin/sql/error/pattern.rb +0 -104
  125. data/lib/ronin/sql/error/patterns.rb +0 -99
  126. data/lib/ronin/sql/extensions.rb +0 -22
  127. data/lib/ronin/sql/extensions/uri.rb +0 -22
  128. data/lib/ronin/sql/extensions/uri/http.rb +0 -107
  129. data/spec/code/sql/common_dialect_spec.rb +0 -205
  130. data/spec/code/sql/create_examples.rb +0 -19
  131. data/spec/code/sql/create_index_spec.rb +0 -25
  132. data/spec/code/sql/create_table_spec.rb +0 -27
  133. data/spec/code/sql/create_view_spec.rb +0 -16
  134. data/spec/code/sql/delete_spec.rb +0 -14
  135. data/spec/code/sql/drop_examples.rb +0 -10
  136. data/spec/code/sql/drop_index_spec.rb +0 -16
  137. data/spec/code/sql/drop_table_spec.rb +0 -16
  138. data/spec/code/sql/drop_view_spec.rb +0 -16
  139. data/spec/code/sql/has_default_values_clause_examples.rb +0 -10
  140. data/spec/code/sql/has_fields_clause_examples.rb +0 -15
  141. data/spec/code/sql/has_from_clause_examples.rb +0 -13
  142. data/spec/code/sql/has_values_clause_examples.rb +0 -15
  143. data/spec/code/sql/has_where_clause_examples.rb +0 -15
  144. data/spec/code/sql/insert_spec.rb +0 -21
  145. data/spec/code/sql/replace_spec.rb +0 -21
  146. data/spec/code/sql/select_spec.rb +0 -105
  147. data/spec/code/sql/update_spec.rb +0 -26
  148. data/spec/helpers/code.rb +0 -14
  149. data/spec/sql/error_spec.rb +0 -24
  150. data/spec/sql/extensions/uri/http_spec.rb +0 -34
  151. data/spec/sql_spec.rb +0 -9
  152. data/tasks/spec.rb +0 -10
  153. data/tasks/yard.rb +0 -13
  154. metadata.gz.sig +0 -0
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+ require 'ronin/sql/field'
3
+
4
+ describe SQL::Field do
5
+ describe "#initialize" do
6
+ it "should convert name to a String" do
7
+ described_class.new(:table).name.should == 'table'
8
+ end
9
+
10
+ it "should default parent to nil" do
11
+ described_class.new('table').parent.should be_nil
12
+ end
13
+ end
14
+
15
+ describe "parse" do
16
+ context "when passed a single field" do
17
+ let(:name) { "column" }
18
+
19
+ subject { described_class.parse(name) }
20
+
21
+ it "should parse the field name" do
22
+ subject.name.should == name
23
+ end
24
+
25
+ it "should not have a parent" do
26
+ subject.parent.should be_nil
27
+ end
28
+ end
29
+
30
+ context "when parsing multiple fields" do
31
+ let(:parent) { "table" }
32
+ let(:name) { "column" }
33
+
34
+ subject { described_class.parse("#{parent}.#{name}") }
35
+
36
+ it "should parse the field name" do
37
+ subject.name.should == name
38
+ end
39
+
40
+ it "should parse the parent field" do
41
+ subject.parent.name.should == parent
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "#to_s" do
47
+ context "when parent is nil" do
48
+ let(:name) { "column" }
49
+
50
+ subject { described_class.new(name) }
51
+
52
+ it "should return the name" do
53
+ subject.to_s.should == name
54
+ end
55
+ end
56
+
57
+ context "when parent is set" do
58
+ let(:parent) { "table" }
59
+ let(:name) { "column" }
60
+
61
+ subject { described_class.new(name,described_class.new(parent)) }
62
+
63
+ it "should return the name" do
64
+ subject.to_s.should == "#{parent}.#{name}"
65
+ end
66
+ end
67
+ end
68
+
69
+ describe "#method_missing" do
70
+ context "at depth 1" do
71
+ subject { described_class.new('table') }
72
+
73
+ it "should allow accessing sub-fields" do
74
+ subject.column.name.should == 'column'
75
+ end
76
+ end
77
+
78
+ context "at depth 2" do
79
+ subject { described_class.new('table',described_class.new('db')) }
80
+
81
+ it "should allow accessing sub-fields" do
82
+ subject.column.name.should == 'column'
83
+ end
84
+ end
85
+
86
+ context "at depth 3" do
87
+ subject do
88
+ described_class.new(
89
+ 'column',
90
+ described_class.new(
91
+ 'table', described_class.new('db')
92
+ )
93
+ )
94
+ end
95
+
96
+ it "should not allow accessing sub-fields" do
97
+ lambda {
98
+ subject.column
99
+ }.should raise_error(NoMethodError)
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ require 'ronin/sql/fields'
3
+
4
+ describe SQL::Fields do
5
+ subject { Object.new.extend(described_class) }
6
+
7
+ describe "#respond_to_missing?" do
8
+ it "should return true" do
9
+ subject.respond_to_missing?(double(:method)).should be(true)
10
+ end
11
+ end
12
+
13
+ its(:to_ary) { should be_nil }
14
+
15
+ describe "#method_missing" do
16
+ let(:name) { 'users' }
17
+
18
+ context "when called with no arguments and no block" do
19
+ it "should create a Field" do
20
+ subject.send(name).name.should == name
21
+ end
22
+ end
23
+
24
+ context "when called with arguments" do
25
+ it "should raise a NoMethodError" do
26
+ lambda {
27
+ subject.sned(name,1,2,3)
28
+ }.should raise_error(NoMethodError)
29
+ end
30
+ end
31
+
32
+ context "when called with a block" do
33
+ it "should raise a NoMethodError" do
34
+ lambda {
35
+ subject.sned(name) { 1 + 1 }
36
+ }.should raise_error(NoMethodError)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for "Function" do |method,arguments=[],additional_arguments=[]|
4
+ describe "##{method}" do
5
+ let(:name) { method.upcase }
6
+ let(:func) { subject.send(method,*arguments) }
7
+
8
+ it "should create a #{method.upcase} function" do
9
+ func.name.should == name
10
+ end
11
+
12
+ unless arguments.empty?
13
+ it "should set the arguments" do
14
+ func.arguments.should == arguments
15
+ end
16
+ end
17
+
18
+ unless additional_arguments.empty?
19
+ context "when passed additional arguments" do
20
+ let(:func) { subject.send(method,*additional_arguments) }
21
+
22
+ it "should set the arguments" do
23
+ func.arguments.should == additional_arguments
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ require 'ronin/sql/function'
4
+
5
+ describe SQL::Function do
6
+ describe "#initialize" do
7
+ context "with no arguments" do
8
+ subject { described_class.new(:f) }
9
+
10
+ it "should set arguments to []" do
11
+ subject.arguments.should == []
12
+ end
13
+ end
14
+
15
+ context "with multiple arguments" do
16
+ let(:arguments) { [1,2,3] }
17
+
18
+ subject { described_class.new(:f,*arguments) }
19
+
20
+ it "should set arguments" do
21
+ subject.arguments.should == arguments
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,110 @@
1
+ require 'spec_helper'
2
+ require 'sql/function_examples'
3
+ require 'ronin/sql/functions'
4
+ require 'ronin/sql/binary_expr'
5
+
6
+ describe SQL::Functions do
7
+ subject { Object.new.extend(described_class) }
8
+
9
+ describe "#count" do
10
+ it "should create a COUNT function" do
11
+ subject.count.name.should == :COUNT
12
+ end
13
+
14
+ context "without arguments" do
15
+ it "should default arguments to *" do
16
+ subject.count.arguments.should == [:*]
17
+ end
18
+ end
19
+ end
20
+
21
+ include_examples "Function", :max, [:column]
22
+ include_examples "Function", :min, [:column]
23
+ include_examples "Function", :avg, [:column]
24
+ include_examples "Function", :sum, [:column]
25
+ include_examples "Function", :sqrt, [1]
26
+ include_examples "Function", :rand, [1]
27
+ include_examples "Function", :abs, [-1]
28
+ include_examples "Function", :acos, [30]
29
+ include_examples "Function", :asin, [30]
30
+ include_examples "Function", :atan, [30]
31
+ include_examples "Function", :atan2, [30,60]
32
+ include_examples "Function", :bit_and, [0xff]
33
+ include_examples "Function", :bit_count, [0xff]
34
+ include_examples "Function", :bit_or, [0xff]
35
+ include_examples "Function", :ceil, [0.5]
36
+ include_examples "Function", :ceiling, [0.5]
37
+ include_examples "Function", :cos, [0.5]
38
+ include_examples "Function", :cot, [0.5]
39
+ include_examples "Function", :degrees, [0.5]
40
+ include_examples "Function", :exp, [0.5]
41
+ include_examples "Function", :floor, [0.5]
42
+ include_examples "Function", :format, [:date, 'YYYY-MM-DD']
43
+ include_examples "Function", :greatest, [1,2,3,4]
44
+ include_examples "Function", :interval, [1,2,3,4]
45
+ include_examples "Function", :least, [1,2,3,4]
46
+ include_examples "Function", :log, [2], [10,2]
47
+ include_examples "Function", :log10, [2]
48
+ include_examples "Function", :mod, [2,10]
49
+ include_examples "Function", :pi
50
+ include_examples "Function", :pow, [2,10]
51
+ include_examples "Function", :power, [2,10]
52
+ include_examples "Function", :radians, [30]
53
+ include_examples "Function", :random
54
+ include_examples "Function", :round, [15.79], [15.79, 1]
55
+ include_examples "Function", :sign, [10]
56
+ include_examples "Function", :sin, [30]
57
+ include_examples "Function", :sqrt, [100]
58
+ include_examples "Function", :std, [:column]
59
+ include_examples "Function", :stddev, [:column]
60
+ include_examples "Function", :tan, [30]
61
+ include_examples "Function", :truncate, [:price,2]
62
+ include_examples "Function", :ascii, ["hello"]
63
+ include_examples "Function", :bin, [12]
64
+ include_examples "Function", :bit_length, ["hello"]
65
+ include_examples "Function", :char, [104, 101, 108, 108, 111]
66
+ include_examples "Function", :char_length, ["hello"]
67
+ include_examples "Function", :character_length, ["hello"]
68
+ include_examples "Function", :concat, ["he", "ll", "o"]
69
+ include_examples "Function", :concat_ws, ["he", "ll", "o"]
70
+ include_examples "Function", :conv, ["ff", 16, 10]
71
+ include_examples "Function", :elt, ["ff", 16, 10]
72
+ include_examples "Function", :export_set, [5, 'Y', 'N']
73
+ include_examples "Function", :field, ["hello", "lo"]
74
+ include_examples "Function", :find_in_set, ['b', 'a,b,c,d']
75
+ include_examples "Function", :glob, [:name, '*foo*']
76
+ include_examples "Function", :hex, ["hello"]
77
+ include_examples "Function", :insert, ["hello",1,2,"foo"]
78
+ include_examples "Function", :instr, ["hello","lo"]
79
+ include_examples "Function", :lcase, ["HELLO"]
80
+ include_examples "Function", :left, ["hello", 10]
81
+ include_examples "Function", :length, ["hello"]
82
+ include_examples "Function", :like, [:name, '%foo%']
83
+ include_examples "Function", :load_file, ["path"]
84
+ include_examples "Function", :locate, ["o", "hello"]
85
+ include_examples "Function", :lower, ["HELLO"]
86
+ include_examples "Function", :lpad, ["hello", 10, ' ']
87
+ include_examples "Function", :ltrim, [" hello"]
88
+ include_examples "Function", :make_set, [8|1, 'a', 'b', 'c', 'd']
89
+ include_examples "Function", :mid, ["hello",2,3]
90
+ include_examples "Function", :oct, ["55"]
91
+ include_examples "Function", :octet_length, ["55"]
92
+ include_examples "Function", :ord, ["55"]
93
+ include_examples "Function", :position, [SQL::BinaryExpr.new('55',:IN,:name)]
94
+ include_examples "Function", :quote, ["hello"]
95
+ include_examples "Function", :repeat, ["A", 100]
96
+ include_examples "Function", :replace, ["foox", "foo", "bar"]
97
+ include_examples "Function", :reverse, ["hello"]
98
+ include_examples "Function", :right, ["hello", 10]
99
+ include_examples "Function", :rpad, ["hello", 10, ' ']
100
+ include_examples "Function", :rtrim, ["hello "]
101
+ include_examples "Function", :soundex, ["smythe"]
102
+ include_examples "Function", :space, [10]
103
+ include_examples "Function", :strcmp, ['foo', 'foox']
104
+ include_examples "Function", :substring, ['hello', 2, 1]
105
+ include_examples "Function", :substring_index, ['foo-bar', '-', 1]
106
+ include_examples "Function", :trim, [' foo ']
107
+ include_examples "Function", :ucase, ['foo']
108
+ include_examples "Function", :unhex, ['4D7953514C']
109
+ include_examples "Function", :upper, ['hello']
110
+ end
@@ -0,0 +1,233 @@
1
+ require 'spec_helper'
2
+ require 'ronin/sql/injection'
3
+
4
+ describe SQL::Injection do
5
+ describe "PLACE_HOLDERS" do
6
+ subject { described_class::PLACE_HOLDERS }
7
+
8
+ it { should include(integer: 1) }
9
+ it { should include(decimal: 1.0) }
10
+ it { should include(string: '1') }
11
+ it { should include(list: [nil]) }
12
+ it { should include(column: :id) }
13
+ end
14
+
15
+ describe "#initialize" do
16
+ context "with no arguments" do
17
+ its(:escape) { should == :integer }
18
+ its(:place_holder) { should == 1 }
19
+ end
20
+
21
+ context "with :escape" do
22
+ context "with no :place_holder" do
23
+ let(:place_holders) { described_class::PLACE_HOLDERS }
24
+ let(:escape) { :string }
25
+
26
+ subject { described_class.new(:escape => escape) }
27
+
28
+ it "should default the place_holder based on the :escape type" do
29
+ subject.place_holder.should == place_holders[escape]
30
+ end
31
+ end
32
+ end
33
+
34
+ context "with :place_holder" do
35
+ let(:data) { 'A' }
36
+
37
+ subject { described_class.new(:place_holder => data) }
38
+
39
+ its(:place_holder) { should == data }
40
+ its(:expression) { should == data }
41
+ end
42
+
43
+ context "when a block is given" do
44
+ subject { described_class.new { @x = 1 } }
45
+
46
+ it "should instance_eval the block" do
47
+ subject.instance_variable_get(:@x).should == 1
48
+ end
49
+ end
50
+ end
51
+
52
+ describe "#and" do
53
+ context "on first call" do
54
+ before { subject.and { 1 } }
55
+
56
+ it "should create a 'AND' BinaryExpr" do
57
+ subject.expression.operator.should == :AND
58
+ end
59
+
60
+ it "should create an expression with the place-holder" do
61
+ subject.expression.left.should == subject.place_holder
62
+ end
63
+
64
+ it "should create an expression with the expression" do
65
+ subject.expression.right.should == 1
66
+ end
67
+ end
68
+
69
+ context "on multiple calls" do
70
+ before { subject.and { 1 }.and { 2 } }
71
+
72
+ it "should create another 'AND' BinaryExpr" do
73
+ subject.expression.operator.should == :AND
74
+ end
75
+
76
+ it "should nest the expressions" do
77
+ subject.expression.left.right.should == 1
78
+ subject.expression.right.should == 2
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "#or" do
84
+ context "on first call" do
85
+ before { subject.or { 1 } }
86
+
87
+ it "should create a 'OR' BinaryExpr" do
88
+ subject.expression.operator.should == :OR
89
+ end
90
+
91
+ it "should create an expression with the place-holder" do
92
+ subject.expression.left.should == subject.place_holder
93
+ end
94
+
95
+ it "should create an expression with the expression" do
96
+ subject.expression.right.should == 1
97
+ end
98
+ end
99
+
100
+ context "on multiple calls" do
101
+ before { subject.or { 1 }.or { 2 } }
102
+
103
+ it "should create another 'OR' BinaryExpr" do
104
+ subject.expression.operator.should == :OR
105
+ end
106
+
107
+ it "should nest the expressions" do
108
+ subject.expression.left.right.should == 1
109
+ subject.expression.right.should == 2
110
+ end
111
+ end
112
+ end
113
+
114
+ describe "#to_sql" do
115
+ context "without an expression" do
116
+ subject { described_class.new(place_holder: 1) }
117
+
118
+ it "should still emit the place-holder value" do
119
+ subject.to_sql.should == '1'
120
+ end
121
+
122
+ context "with clauses" do
123
+ subject do
124
+ sqli = described_class.new(place_holder: 1)
125
+ sqli.limit(100).offset(10)
126
+ sqli
127
+ end
128
+
129
+ it "should emit the clauses" do
130
+ subject.to_sql.should == '1 LIMIT 100 OFFSET 10'
131
+ end
132
+ end
133
+ end
134
+
135
+ context "with an expression" do
136
+ subject do
137
+ sqli = described_class.new
138
+ sqli.or { 1 == 1 }
139
+ sqli
140
+ end
141
+
142
+ it "should emit the expression" do
143
+ subject.to_sql.should == '1 OR 1=1'
144
+ end
145
+
146
+ context "with clauses" do
147
+ subject do
148
+ sqli = described_class.new
149
+ sqli.or { 1 == 1 }.limit(100).offset(10)
150
+ sqli
151
+ end
152
+
153
+ it "should emit the clauses" do
154
+ subject.to_sql.should == '1 OR 1=1 LIMIT 100 OFFSET 10'
155
+ end
156
+
157
+ context "with :space" do
158
+ it "should emit the clauses with custom spaces" do
159
+ subject.to_sql(space: '/**/').should == '1/**/OR/**/1=1/**/LIMIT/**/100/**/OFFSET/**/10'
160
+ end
161
+ end
162
+ end
163
+
164
+ context "with statements" do
165
+ subject do
166
+ sqli = described_class.new
167
+ sqli.or { 1 == 1 }.select(1,2,3)
168
+ sqli
169
+ end
170
+
171
+ it "should emit the clauses" do
172
+ subject.to_sql.should == '1 OR 1=1; SELECT (1,2,3)'
173
+ end
174
+
175
+ context "with :space" do
176
+ it "should emit the statements with custom spaces" do
177
+ subject.to_sql(space: '/**/').should == '1/**/OR/**/1=1;/**/SELECT/**/(1,2,3)'
178
+ end
179
+ end
180
+ end
181
+ end
182
+
183
+ context "when escaping a string value" do
184
+ context "when the place-holder and last operand are Strings" do
185
+ subject do
186
+ sqli = described_class.new(escape: :string)
187
+ sqli.or { string(1) == string(1) }
188
+ sqli
189
+ end
190
+
191
+ it "should balance the quotes" do
192
+ subject.to_sql.should == "1' OR '1'='1"
193
+ end
194
+ end
195
+
196
+ context "when the place-holder and last operand are not both Strings" do
197
+ subject do
198
+ sqli = described_class.new(escape: :string)
199
+ sqli.or { int(1) == int(1) }
200
+ sqli
201
+ end
202
+
203
+ it "should terminate the SQL statement" do
204
+ subject.to_sql.should == "1' OR 1=1;--"
205
+ end
206
+ end
207
+
208
+ context "when terminating" do
209
+ subject do
210
+ sqli = described_class.new(escape: :string)
211
+ sqli.or { string(1) == string(1) }
212
+ sqli
213
+ end
214
+
215
+ it "should terminate the SQL statement" do
216
+ subject.to_sql(terminate: true).should == "1' OR '1'='1';--"
217
+ end
218
+ end
219
+ end
220
+
221
+ context "when terminating" do
222
+ subject do
223
+ sqli = described_class.new(escape: :integer)
224
+ sqli.or { 1 == 1 }
225
+ sqli
226
+ end
227
+
228
+ it "should terminate the SQL statement" do
229
+ subject.to_sql(terminate: true).should == "1 OR 1=1;--"
230
+ end
231
+ end
232
+ end
233
+ end