ronin-sql 0.2.4 → 1.0.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.
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