sqldsl 1.2.2 → 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.
data/README CHANGED
@@ -21,6 +21,11 @@ See the tests for more examples
21
21
  === Test Helper
22
22
 
23
23
  require 'test/unit'
24
+ unless File.directory? File.dirname(__FILE__) + '/../vendor/mocha-0.4.0/'
25
+ raise "mocha 4.0 is required to run the test suite. create the 'vendor' directory as a sibling of test and 'gem unpack mocha' in 'vendor'"
26
+ end
27
+ $:.unshift File.dirname(__FILE__) + '/../vendor/mocha-0.4.0/lib/'
28
+ require File.dirname(__FILE__) + '/../vendor/mocha-0.4.0/lib/mocha'
24
29
  require File.dirname(__FILE__) + '/../lib/sqldsl'
25
30
 
26
31
  === Insert Example
@@ -72,22 +77,102 @@ See the tests for more examples
72
77
  require File.dirname(__FILE__) + '/test_helper'
73
78
 
74
79
  class SelectAcceptanceTest < Test::Unit::TestCase
75
- def test_simple_select
76
- statement = Select[:column1, 'book', 10].from[:table1].where do
80
+ def test_select_with_where_methods
81
+ statement = Select[:column1, 'book', 10].from[:table1, :table2].where do
77
82
  equal :column1, 99
78
- equal :column2, 'star'
83
+ not_equal :column1, 100
84
+ less_than :column2, 'foo'
85
+ less_than_or_equal :column3, :column4
86
+ greater_than :column1, 0
87
+ greater_than_or_equal :column2, 'bar'
88
+ is_not_null :column1
89
+ is_in :column1, [1,2]
90
+ is_not_in :column2, [3, 4]
91
+ exists 0
92
+ not_exists 0
79
93
  end
80
- expected = "select column1, 'book', 10 from table1 where column1 = 99 and column2 = 'star'"
81
- assert_equal expected, statement.to_sql
94
+ expected = "select column1, 'book', 10 from table1, table2
95
+ where column1 = 99 and column1 <> 100 and column2 < 'foo'
96
+ and column3 <= column4 and column1 > 0 and column2 >= 'bar'
97
+ and column1 is not null and column1 in (1, 2) and column2 not in (3, 4)
98
+ and exists (0) and not exists (0)"
99
+ assert_equal expected.delete("\n").squeeze(" "), statement.to_sql
100
+ end
101
+
102
+ def test_select_with_receive_any_objects_and_operators
103
+ statement = Select[:column1, 'book', 10].from[:table1, :table2].where do
104
+ table1.column1 = 99
105
+ column1 <=> 100
106
+ column2 < 'foo'
107
+ column3 <= column4
108
+ column1 > 0
109
+ column2 >= 'bar'
110
+ column1 ^ nil
111
+ column1 >> [1,2]
112
+ column2 << [3, 4]
113
+ end
114
+ expected = "select column1, 'book', 10 from table1, table2
115
+ where table1.column1 = 99 and column1 <> 100 and column2 < 'foo'
116
+ and column3 <= column4 and column1 > 0 and column2 >= 'bar'
117
+ and column1 is not null and column1 in (1, 2) and column2 not in (3, 4)"
118
+ assert_equal expected.delete("\n").squeeze(" "), statement.to_sql
82
119
  end
83
120
 
84
- def test_select_with_join
85
- statement = Select[:column1, :column2].from[:table1, :table2].where do
86
- equal :'table1.id', :'table2.table1_id'
121
+ def test_select_with_receive_any_objects_and_method_calls
122
+ statement = Select[:column1, 'book', 10].from[:table1, :table2].where do
123
+ column1.equal 99
124
+ column1.not_equal 100
125
+ column2.less_than 'foo'
126
+ column3.less_than_or_equal column4
127
+ column1.greater_than 0
128
+ column2.greater_than_or_equal 'bar'
129
+ column1.is_not_null
130
+ column1.is_in [1,2]
131
+ column2.is_not_in [3, 4]
87
132
  end
88
- expected = "select column1, column2 from table1, table2 where table1.id = table2.table1_id"
133
+ expected = "select column1, 'book', 10 from table1, table2
134
+ where column1 = 99 and column1 <> 100 and column2 < 'foo'
135
+ and column3 <= column4 and column1 > 0 and column2 >= 'bar'
136
+ and column1 is not null and column1 in (1, 2) and column2 not in (3, 4)"
137
+ assert_equal expected.delete("\n").squeeze(" "), statement.to_sql
138
+ end
139
+
140
+ def test_select_with_receive_any_objects_and_method_calls
141
+ statement = Select[:column1, 'book', 10].from[:table1, :table2].where do
142
+ column1.equal 0
143
+ end.or do
144
+ column1 > 100
145
+ end
146
+ expected = "select column1, 'book', 10 from table1, table2 where column1 = 0 or column1 > 100"
89
147
  assert_equal expected, statement.to_sql
90
148
  end
149
+
150
+ def test_columns_in_inner_where_are_validated_against_outer_tables
151
+ statement = Select.all.from[:table].where do
152
+ exists(Select.all.from[:inner_table => :aliased].where do
153
+ table.column1 = aliased.column1
154
+ end)
155
+ end
156
+ assert_equal 'select * from table where exists (select * from inner_table aliased where table.column1 = aliased.column1)', statement.to_sql
157
+ end
158
+
159
+ def test_columns_in_where_are_validated_against_tables
160
+ assert_raises ArgumentError do
161
+ Select.all.from[:table].where do
162
+ not_table.cat = 12
163
+ end
164
+ end
165
+ end
166
+
167
+ def test_columns_in_inner_where_are_validated_against_outer_and_inner_tables
168
+ assert_raises ArgumentError do
169
+ Select.all.from[:table].where do
170
+ exists(Select.all.from[:inner_table].where do
171
+ table.column1 = not_table.cat
172
+ end)
173
+ end
174
+ end
175
+ end
91
176
  end
92
177
 
93
178
  === Contributors
data/lib/array.rb CHANGED
@@ -8,13 +8,4 @@ class Array
8
8
  def to_sql
9
9
  self.collect { |element| element.to_sql }.join(', ')
10
10
  end
11
-
12
- # call-seq: array.to_sql_equal(any) -> a_string
13
- #
14
- # Returns a string containing the sql in expression
15
- #
16
- # [10, :column2, 'book'].to_sql_equal(:column1) #=> "column1 in (10, column2, 'book')"
17
- def to_sql_equal(lval)
18
- "#{lval.to_sql } in (#{ self.to_sql })"
19
- end
20
11
  end
data/lib/delete.rb CHANGED
@@ -17,6 +17,7 @@ class Delete < SqlStatement
17
17
  # Delete.from[:table1].to_sql #=> "delete from table1"
18
18
  def [](table)
19
19
  @to_sql += table.to_sql
20
+ @tables = [table]
20
21
  self
21
22
  end
22
23
  end
data/lib/numeric.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  class Numeric
2
- include WhereValue
3
2
  # call-seq: numeric.to_sql -> a_numeric
4
3
  #
5
4
  # Returns self
@@ -0,0 +1,15 @@
1
+ class OrWhereBuilder < WhereBuilder
2
+
3
+ # call-seq: or_where.to_sql -> a_string
4
+ #
5
+ # Returns a string by collecting all the conditions and joins them with ' and '.
6
+ #
7
+ # OrWhereBuilder.new [] do
8
+ # equal :column1, 10
9
+ # equal :column2, 'book'
10
+ # end.to_sql #=> " or column1 = 10 and column2 = 'book'"
11
+ def to_sql
12
+ " or #{sql_parts.join(' and ')}"
13
+ end
14
+
15
+ end
data/lib/receive_any.rb CHANGED
@@ -1,26 +1,59 @@
1
1
  class ReceiveAny #:nodoc:
2
- attr_reader :to_sql
2
+ attr_reader :to_sql, :builder
3
3
 
4
4
  def initialize(identifier, builder)
5
5
  @to_sql = identifier.to_s
6
6
  @builder = builder
7
7
  end
8
8
 
9
- def <=(arg)
10
- @builder.sql_parts << "#{self.to_sql} <= #{arg.to_sql}"
9
+ def equal(arg)
10
+ builder.equal self, arg
11
11
  end
12
12
 
13
- def >=(arg)
14
- @builder.sql_parts << "#{self.to_sql} >= #{arg.to_sql}"
13
+ def not_equal(arg)
14
+ builder.not_equal self, arg
15
15
  end
16
+ alias <=> not_equal
16
17
 
17
- def append_on_setter(lval, rval)
18
- @builder.equal(lval.to_sym, rval)
18
+ def less_than(arg)
19
+ builder.less_than self, arg
19
20
  end
21
+ alias < less_than
22
+
23
+ def less_than_or_equal(arg)
24
+ builder.less_than_or_equal self, arg
25
+ end
26
+ alias <= less_than_or_equal
27
+
28
+ def greater_than(arg)
29
+ builder.greater_than self, arg
30
+ end
31
+ alias > greater_than
32
+
33
+ def greater_than_or_equal(arg)
34
+ builder.greater_than_or_equal self, arg
35
+ end
36
+ alias >= greater_than_or_equal
37
+
38
+ def is_in(arg)
39
+ builder.is_in self, arg
40
+ end
41
+ alias >> is_in
42
+
43
+ def is_not_in(arg)
44
+ builder.is_not_in self, arg
45
+ end
46
+ alias << is_not_in
47
+
48
+ def is_not_null(arg=nil)
49
+ builder.is_not_null self
50
+ end
51
+ alias ^ is_not_null
20
52
 
21
53
  def method_missing(sym, *args)
54
+ raise ArgumentError.new("#{self.to_sql} is not specified as a table in your from statement") unless @builder.tables.include?(self.to_sql.to_sym)
22
55
  @to_sql << ".#{sym.to_s}".chomp("=")
23
- append_on_setter(self.to_sql, args.first) if sym.to_s =~ /=$/
56
+ self.equal args.first if sym.to_s =~ /=$/
24
57
  self
25
58
  end
26
59
  end
data/lib/select.rb CHANGED
@@ -45,7 +45,11 @@ class Select < SqlStatement
45
45
  #
46
46
  # Select[1, :column1, 'book'].from[:table1, :table2].to_sql #=> "select 1, column1, 'book' from table1, table2"
47
47
  def [](*table_names)
48
- @to_sql += table_names.sort{ |x,y| x.to_s <=> y.to_s }.to_sql
48
+ @tables = table_names.inject([]) { |result, element| result + (element.is_a?(Hash) ? element.values : [element]) }
49
+
50
+ @to_sql += table_names.inject([]) do |result, element|
51
+ result + (element.is_a?(Symbol) ? [element] : element.to_a.inject([]) { |result, pair| result << :"#{pair.first} #{pair.last}" })
52
+ end.sort{ |x,y| x.to_s <=> y.to_s }.to_sql
49
53
  self
50
54
  end
51
55
 
data/lib/sql_statement.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  class SqlStatement
2
+ attr_accessor :tables
2
3
  attr_reader :to_sql
3
4
 
4
5
  def initialize(sql) #:nodoc:
@@ -13,7 +14,19 @@ class SqlStatement
13
14
  #
14
15
  # Select[1].where { equal :column1, 1 }.to_sql #=> "select 1 where column1 = 1"
15
16
  def where(&block)
16
- @to_sql += WhereBuilder.new(&block).to_sql
17
+ @to_sql += WhereBuilder.new(self.tables, &block).to_sql
18
+ self
19
+ end
20
+
21
+ # call-seq: sql_statement.or { block } -> a_sql_statement
22
+ #
23
+ # Creates a new OrWhereBuilder instance, passing the block as a parameter, then executes to_sql on the OrWhereBuilder instance.
24
+ # The resulting string from the OrWhereBuilder instance is appended to the SQL statement.
25
+ # Returns self.
26
+ #
27
+ # Select[1].where { equal :column1, 1 }.or { equal :column1, 100 }.to_sql #=> "select 1 where column1 = 1 or column1 = 100"
28
+ def or(&block)
29
+ @to_sql += OrWhereBuilder.new(self.tables, &block).to_sql
17
30
  self
18
31
  end
19
32
  end
data/lib/sqldsl.rb CHANGED
@@ -1,6 +1,4 @@
1
1
  require File.dirname(__FILE__) + '/receive_any.rb'
2
- require File.dirname(__FILE__) + '/where_value.rb'
3
- require File.dirname(__FILE__) + '/object.rb'
4
2
  require File.dirname(__FILE__) + '/symbol.rb'
5
3
  require File.dirname(__FILE__) + '/array.rb'
6
4
  require File.dirname(__FILE__) + '/string.rb'
@@ -9,6 +7,7 @@ require File.dirname(__FILE__) + '/numeric.rb'
9
7
  require File.dirname(__FILE__) + '/time.rb'
10
8
  require File.dirname(__FILE__) + '/sql_statement.rb'
11
9
  require File.dirname(__FILE__) + '/where_builder.rb'
10
+ require File.dirname(__FILE__) + '/or_where_builder.rb'
12
11
  require File.dirname(__FILE__) + '/select.rb'
13
12
  require File.dirname(__FILE__) + '/distinct_select.rb'
14
13
  require File.dirname(__FILE__) + '/insert.rb'
data/lib/string.rb CHANGED
@@ -1,6 +1,4 @@
1
1
  class String
2
- include WhereValue
3
-
4
2
  # call-seq: string.to_sql -> a_string
5
3
  #
6
4
  # Returns a string with single quotes escaped.
data/lib/symbol.rb CHANGED
@@ -1,5 +1,4 @@
1
1
  class Symbol
2
- include WhereValue
3
2
  # call-seq: symbol.to_sql -> a_string
4
3
  #
5
4
  # Returns a string with single quotes escaped.
data/lib/update.rb CHANGED
@@ -6,7 +6,9 @@ class Update < SqlStatement
6
6
  #
7
7
  # Update[:table1].to_sql #=> "update table1"
8
8
  def [](table)
9
- self.new("update #{table.to_sql}")
9
+ update = self.new("update #{table.to_sql}")
10
+ update.tables = [table]
11
+ update
10
12
  end
11
13
  end
12
14
 
data/lib/where_builder.rb CHANGED
@@ -1,12 +1,15 @@
1
1
  class WhereBuilder
2
-
3
- # call-seq: WhereBuilder.new(&block) -> a_where_builder
2
+ attr_reader :tables
3
+
4
+ # call-seq: WhereBuilder.new(tables, &block) -> a_where_builder
4
5
  #
5
6
  # Returns a new WhereBuilder. At initialization time the block is instance evaled on the
6
7
  # new WhereBuilder instance.
7
8
  #
8
- # WhereBuilder.new { equal :column1, 10 }.to_sql #=> " where column1 = 10"
9
- def initialize(&block)
9
+ # WhereBuilder.new [:table1] { equal :column1, 10 }.to_sql #=> " where column1 = 10"
10
+ def initialize(tables, &block)
11
+ raise ArgumentError.new("no block given to where, check for parenthesis usage") unless block_given?
12
+ @tables = tables.concat(eval("respond_to?(:tables) ? tables : []", block.binding))
10
13
  instance_eval(&block)
11
14
  end
12
15
 
@@ -14,25 +17,88 @@ class WhereBuilder
14
17
  #
15
18
  # Appends an equality condition to the where SQL clause.
16
19
  #
17
- # WhereBuilder.new { equal :column1, 10 }.to_sql #=> " where column1 = 10"
20
+ # where { equal :column1, 10 }.to_sql #=> " where column1 = 10"
18
21
  def equal(lval, rval)
19
- sql_parts << rval.to_sql_equal(lval)
22
+ add_condition(lval, "=", rval)
23
+ end
24
+
25
+ # call-seq: where.not_equal(arg1, arg2)
26
+ #
27
+ # Appends a not equal condition to the where SQL clause.
28
+ #
29
+ # where { not_equal :column1, 10 }.to_sql #=> " where column1 <> 10"
30
+ def not_equal(lval, rval)
31
+ add_condition(lval, "<>", rval)
32
+ end
33
+
34
+ # call-seq: where.less_than(arg1, arg2)
35
+ #
36
+ # Appends a less than condition to the where SQL clause.
37
+ #
38
+ # where { less_than :column1, 10 }.to_sql #=> " where column1 < 10"
39
+ def less_than(lval, rval)
40
+ add_condition(lval, "<", rval)
41
+ end
42
+
43
+ # call-seq: where.less_than_or_equal(arg1, arg2)
44
+ #
45
+ # Appends a less than or equal condition to the where SQL clause.
46
+ #
47
+ # where { less_than_or_equal :column1, 10 }.to_sql #=> " where column1 <= 10"
48
+ def less_than_or_equal(lval, rval)
49
+ add_condition(lval, "<=", rval)
50
+ end
51
+
52
+ # call-seq: where.greater_than(arg1, arg2)
53
+ #
54
+ # Appends a greater than condition to the where SQL clause.
55
+ #
56
+ # where { greater_than :column1, 10 }.to_sql #=> " where column1 > 10"
57
+ def greater_than(lval, rval)
58
+ add_condition(lval, ">", rval)
59
+ end
60
+
61
+ # call-seq: where.greater_than_or_equal(arg1, arg2)
62
+ #
63
+ # Appends a greater than or equal condition to the where SQL clause.
64
+ #
65
+ # where { greater_than_or_equal :column1, 10 }.to_sql #=> " where column1 >= 10"
66
+ def greater_than_or_equal(lval, rval)
67
+ add_condition(lval, ">=", rval)
68
+ end
69
+
70
+ # call-seq: where.is_in(arg1, arg2)
71
+ #
72
+ # Appends an in condition to the where SQL clause.
73
+ #
74
+ # where { is_in :column1, [10, 20] }.to_sql #=> " where column1 in (10, 20)"
75
+ def is_in(lval, rval)
76
+ add_parenthesis_condition(lval, "in", rval)
77
+ end
78
+
79
+ # call-seq: where.is_not_in(arg1, arg2)
80
+ #
81
+ # Appends a not in condition to the where SQL clause.
82
+ #
83
+ # where { is_not_in :column1, [10, 20] }.to_sql #=> " where column1 not in (10, 20)"
84
+ def is_not_in(lval, rval)
85
+ add_parenthesis_condition(lval, "not in", rval)
20
86
  end
21
87
 
22
88
  # call-seq: where.not_null(arg1)
23
89
  #
24
90
  # Appends a not null condition to the where SQL clause.
25
91
  #
26
- # WhereBuilder.new { not_null :column1 }.to_sql #=> " where column1 is not null"
27
- def not_null(column)
28
- sql_parts << "#{column} is not null"
92
+ # where { is_not_null :column1 }.to_sql #=> " where column1 is not null"
93
+ def is_not_null(column)
94
+ sql_parts << "#{column.to_sql} is not null"
29
95
  end
30
96
 
31
97
  # call-seq: where.exists(clause)
32
98
  #
33
99
  # Appends an exists condition to the where SQL clause.
34
100
  #
35
- # WhereBuilder.new { exists 'select id from table1' }.to_sql #=> " where exists (select id from table1)"
101
+ # where { exists 'select id from table1' }.to_sql #=> " where exists (select id from table1)"
36
102
  def exists(clause)
37
103
  sql_parts << "exists (#{clause.to_sql})"
38
104
  end
@@ -41,7 +107,7 @@ class WhereBuilder
41
107
  #
42
108
  # Appends an exists condition to the where SQL clause.
43
109
  #
44
- # WhereBuilder.new { not_exists 'select id from table1' }.to_sql #=> " where not exists (select id from table1)"
110
+ # where { not_exists 'select id from table1' }.to_sql #=> " where not exists (select id from table1)"
45
111
  def not_exists(clause)
46
112
  sql_parts << "not exists (#{clause.to_sql})"
47
113
  end
@@ -50,7 +116,7 @@ class WhereBuilder
50
116
  #
51
117
  # Returns a string by collecting all the conditions and joins them with ' and '.
52
118
  #
53
- # WhereBuilder.new do
119
+ # WhereBuilder.new [] do
54
120
  # equal :column1, 10
55
121
  # equal :column2, 'book'
56
122
  # end.to_sql #=> " where column1 = 10 and column2 = 'book'"
@@ -58,12 +124,21 @@ class WhereBuilder
58
124
  " where #{sql_parts.join(' and ')}"
59
125
  end
60
126
 
127
+ def add_condition(lval, operator, rval) #:nodoc:
128
+ sql_parts << "#{lval.to_sql} #{operator} #{rval.to_sql}"
129
+ end
130
+
131
+ def add_parenthesis_condition(lval, operator, rval) #:nodoc:
132
+ sql_parts << "#{lval.to_sql} #{operator} (#{rval.to_sql})"
133
+ end
134
+
135
+ protected
61
136
  def sql_parts #:nodoc:
62
137
  @sql_parts ||= []
63
138
  end
64
139
 
65
140
  def method_missing(sym, *args) #:nodoc:
141
+ super unless args.empty?
66
142
  ReceiveAny.new(sym, self)
67
143
  end
68
-
69
144
  end
data/rakefile.rb CHANGED
@@ -27,7 +27,7 @@ Gem::manage_gems
27
27
  specification = Gem::Specification.new do |s|
28
28
  s.name = "sqldsl"
29
29
  s.summary = "A DSL for creating SQL Statements"
30
- s.version = "1.2.2"
30
+ s.version = "1.3.0"
31
31
  s.author = 'Jay Fields'
32
32
  s.description = "A DSL for creating SQL Statements"
33
33
  s.email = 'sqldsl-developer@rubyforge.org'
data/test/all_tests.rb CHANGED
@@ -1 +1 @@
1
- Dir['**/*_test.rb'].each { |testCase| require testCase }
1
+ Dir["#{File.dirname __FILE__}/*_test.rb"].each { |test_case| require test_case }
data/test/array_test.rb CHANGED
@@ -4,8 +4,4 @@ class ArrayTest < Test::Unit::TestCase
4
4
  def test_to_sql_gives_of_to_sql_objects_comma_delimited
5
5
  assert_equal "too, 'the', 2", [:too, 'the', 2].to_sql
6
6
  end
7
-
8
- def test_sql_equal_uses_in
9
- assert_equal "column1 in (too, 'the', 2)", [:too, 'the', 2].to_sql_equal(:column1)
10
- end
11
7
  end
data/test/delete_test.rb CHANGED
@@ -23,7 +23,7 @@ class DeleteTest < Test::Unit::TestCase
23
23
  assert_equal expected, statement.to_sql
24
24
  end
25
25
 
26
- def test_if_where_is_called_with_no_block_gives_reminder_to_use_parents
26
+ def test_if_where_is_called_with_no_block_gives_reminder_to_use_parens
27
27
  assert_raise(ArgumentError) do
28
28
  statement = Delete.from[:potential_account_offers].where do
29
29
  exists Select[:'potential_account_offers.id'].from[:foo].where do
data/test/numeric_test.rb CHANGED
@@ -4,9 +4,4 @@ class NumbericTest < Test::Unit::TestCase
4
4
  def test_to_sql_gives_self
5
5
  assert_equal 123, 123.to_sql
6
6
  end
7
-
8
- def test_is_a_where_value_duck
9
- assert_equal true, 123.respond_to?(:is_not_in)
10
- end
11
-
12
7
  end
@@ -0,0 +1,161 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ReceiveAnyTest < Test::Unit::TestCase
4
+
5
+ def test_method_calls_to_valid_table_names_are_okay
6
+ builder = stub(:tables => [:foo])
7
+ ReceiveAny.new(:foo, builder).column1
8
+ end
9
+
10
+ def test_method_calls_to_invalid_table_names_raise_Argument_Error
11
+ assert_raises ArgumentError do
12
+ builder = stub(:tables => [])
13
+ ReceiveAny.new(:foo, builder).column1
14
+ end
15
+ end
16
+
17
+ def test_equal
18
+ builder = mock
19
+ builder.expects(:equal).with do |lval, rval|
20
+ lval.class == ReceiveAny && rval == 1
21
+ end
22
+ ReceiveAny.new(:foo, builder).equal 1
23
+ end
24
+
25
+ def test_equal_operator
26
+ builder = mock
27
+ builder.expects(:equal).with do |lval, rval|
28
+ lval.class == ReceiveAny && rval == 1
29
+ end
30
+ builder.expects(:tables).returns [:foo]
31
+ ReceiveAny.new(:foo, builder).bar = 1
32
+ end
33
+
34
+ def test_not_equal
35
+ builder = mock
36
+ builder.expects(:not_equal).with do |lval, rval|
37
+ lval.class == ReceiveAny && rval == 1
38
+ end
39
+ ReceiveAny.new(:foo, builder).not_equal 1
40
+ end
41
+
42
+ def test_not_equal_operator
43
+ builder = mock
44
+ builder.expects(:equal).with do |lval, rval|
45
+ lval.class == ReceiveAny && rval == 1
46
+ end
47
+ ReceiveAny.new(:foo, builder) <=> 1
48
+ end
49
+
50
+ def test_less_than
51
+ builder = mock
52
+ builder.expects(:less_than).with do |lval, rval|
53
+ lval.class == ReceiveAny && rval == 1
54
+ end
55
+ ReceiveAny.new(:foo, builder).less_than 1
56
+ end
57
+
58
+ def test_less_than_operator
59
+ builder = mock
60
+ builder.expects(:less_than).with do |lval, rval|
61
+ lval.class == ReceiveAny && rval == 1
62
+ end
63
+ ReceiveAny.new(:foo, builder) < 1
64
+ end
65
+
66
+ def test_less_than_or_equal
67
+ builder = mock
68
+ builder.expects(:less_than_or_equal).with do |lval, rval|
69
+ lval.class == ReceiveAny && rval == 1
70
+ end
71
+ ReceiveAny.new(:foo, builder).less_than_or_equal 1
72
+ end
73
+
74
+ def test_less_than_or_equal_operator
75
+ builder = mock
76
+ builder.expects(:less_than_or_equal).with do |lval, rval|
77
+ lval.class == ReceiveAny && rval == 1
78
+ end
79
+ ReceiveAny.new(:foo, builder) <= 1
80
+ end
81
+
82
+ def test_greater_than
83
+ builder = mock
84
+ builder.expects(:greater_than).with do |lval, rval|
85
+ lval.class == ReceiveAny && rval == 1
86
+ end
87
+ ReceiveAny.new(:foo, builder).greater_than 1
88
+ end
89
+
90
+ def test_greater_than_operator
91
+ builder = mock
92
+ builder.expects(:greater_than).with do |lval, rval|
93
+ lval.class == ReceiveAny && rval == 1
94
+ end
95
+ ReceiveAny.new(:foo, builder) > 1
96
+ end
97
+
98
+ def test_greater_than_or_equal
99
+ builder = mock
100
+ builder.expects(:greater_than_or_equal).with do |lval, rval|
101
+ lval.class == ReceiveAny && rval == 1
102
+ end
103
+ ReceiveAny.new(:foo, builder).greater_than_or_equal 1
104
+ end
105
+
106
+ def test_greater_than_or_equal_operator
107
+ builder = mock
108
+ builder.expects(:greater_than_or_equal).with do |lval, rval|
109
+ lval.class == ReceiveAny && rval == 1
110
+ end
111
+ ReceiveAny.new(:foo, builder) >= 1
112
+ end
113
+
114
+ def test_is_in
115
+ builder = mock
116
+ builder.expects(:is_in).with do |lval, rval|
117
+ lval.class == ReceiveAny && rval == [1,2]
118
+ end
119
+ ReceiveAny.new(:foo, builder).is_in [1,2]
120
+ end
121
+
122
+ def test_is_in_operator
123
+ builder = mock
124
+ builder.expects(:is_in).with do |lval, rval|
125
+ lval.class == ReceiveAny && rval == [1,2]
126
+ end
127
+ ReceiveAny.new(:foo, builder) >> [1,2]
128
+ end
129
+
130
+ def test_is_not_in
131
+ builder = mock
132
+ builder.expects(:is_not_in).with do |lval, rval|
133
+ lval.class == ReceiveAny && rval == [1,2]
134
+ end
135
+ ReceiveAny.new(:foo, builder).is_not_in [1,2]
136
+ end
137
+
138
+ def test_is_not_in_operator
139
+ builder = mock
140
+ builder.expects(:is_not_in).with do |lval, rval|
141
+ lval.class == ReceiveAny && rval == [1,2]
142
+ end
143
+ ReceiveAny.new(:foo, builder) << [1,2]
144
+ end
145
+
146
+ def test_is_not_null
147
+ builder = mock
148
+ builder.expects(:is_not_null).with do |lval|
149
+ lval.class == ReceiveAny
150
+ end
151
+ ReceiveAny.new(:foo, builder).is_not_null
152
+ end
153
+
154
+ def test_is_not_null_operator
155
+ builder = mock
156
+ builder.expects(:is_not_in).with do |lval|
157
+ lval.class == ReceiveAny
158
+ end
159
+ ReceiveAny.new(:foo, builder) ^ nil
160
+ end
161
+ end
@@ -1,20 +1,100 @@
1
1
  require File.dirname(__FILE__) + '/test_helper'
2
2
 
3
3
  class SelectAcceptanceTest < Test::Unit::TestCase
4
- def test_simple_select
5
- statement = Select[:column1, 'book', 10].from[:table1].where do
4
+ def test_select_with_where_methods
5
+ statement = Select[:column1, 'book', 10].from[:table1, :table2].where do
6
6
  equal :column1, 99
7
- equal :column2, 'star'
7
+ not_equal :column1, 100
8
+ less_than :column2, 'foo'
9
+ less_than_or_equal :column3, :column4
10
+ greater_than :column1, 0
11
+ greater_than_or_equal :column2, 'bar'
12
+ is_not_null :column1
13
+ is_in :column1, [1,2]
14
+ is_not_in :column2, [3, 4]
15
+ exists 0
16
+ not_exists 0
8
17
  end
9
- expected = "select column1, 'book', 10 from table1 where column1 = 99 and column2 = 'star'"
10
- assert_equal expected, statement.to_sql
18
+ expected = "select column1, 'book', 10 from table1, table2
19
+ where column1 = 99 and column1 <> 100 and column2 < 'foo'
20
+ and column3 <= column4 and column1 > 0 and column2 >= 'bar'
21
+ and column1 is not null and column1 in (1, 2) and column2 not in (3, 4)
22
+ and exists (0) and not exists (0)"
23
+ assert_equal expected.delete("\n").squeeze(" "), statement.to_sql
24
+ end
25
+
26
+ def test_select_with_receive_any_objects_and_operators
27
+ statement = Select[:column1, 'book', 10].from[:table1, :table2].where do
28
+ table1.column1 = 99
29
+ column1 <=> 100
30
+ column2 < 'foo'
31
+ column3 <= column4
32
+ column1 > 0
33
+ column2 >= 'bar'
34
+ column1 ^ nil
35
+ column1 >> [1,2]
36
+ column2 << [3, 4]
37
+ end
38
+ expected = "select column1, 'book', 10 from table1, table2
39
+ where table1.column1 = 99 and column1 <> 100 and column2 < 'foo'
40
+ and column3 <= column4 and column1 > 0 and column2 >= 'bar'
41
+ and column1 is not null and column1 in (1, 2) and column2 not in (3, 4)"
42
+ assert_equal expected.delete("\n").squeeze(" "), statement.to_sql
11
43
  end
12
44
 
13
- def test_select_with_join
14
- statement = Select[:column1, :column2].from[:table1, :table2].where do
15
- equal :'table1.id', :'table2.table1_id'
45
+ def test_select_with_receive_any_objects_and_method_calls
46
+ statement = Select[:column1, 'book', 10].from[:table1, :table2].where do
47
+ column1.equal 99
48
+ column1.not_equal 100
49
+ column2.less_than 'foo'
50
+ column3.less_than_or_equal column4
51
+ column1.greater_than 0
52
+ column2.greater_than_or_equal 'bar'
53
+ column1.is_not_null
54
+ column1.is_in [1,2]
55
+ column2.is_not_in [3, 4]
16
56
  end
17
- expected = "select column1, column2 from table1, table2 where table1.id = table2.table1_id"
57
+ expected = "select column1, 'book', 10 from table1, table2
58
+ where column1 = 99 and column1 <> 100 and column2 < 'foo'
59
+ and column3 <= column4 and column1 > 0 and column2 >= 'bar'
60
+ and column1 is not null and column1 in (1, 2) and column2 not in (3, 4)"
61
+ assert_equal expected.delete("\n").squeeze(" "), statement.to_sql
62
+ end
63
+
64
+ def test_select_with_receive_any_objects_and_method_calls
65
+ statement = Select[:column1, 'book', 10].from[:table1, :table2].where do
66
+ column1.equal 0
67
+ end.or do
68
+ column1 > 100
69
+ end
70
+ expected = "select column1, 'book', 10 from table1, table2 where column1 = 0 or column1 > 100"
18
71
  assert_equal expected, statement.to_sql
19
72
  end
73
+
74
+ def test_columns_in_inner_where_are_validated_against_outer_tables
75
+ statement = Select.all.from[:table].where do
76
+ exists(Select.all.from[:inner_table => :aliased].where do
77
+ table.column1 = aliased.column1
78
+ end)
79
+ end
80
+ assert_equal 'select * from table where exists (select * from inner_table aliased where table.column1 = aliased.column1)', statement.to_sql
81
+ end
82
+
83
+ def test_columns_in_where_are_validated_against_tables
84
+ assert_raises ArgumentError do
85
+ Select.all.from[:table].where do
86
+ not_table.cat = 12
87
+ end
88
+ end
89
+ end
90
+
91
+ def test_columns_in_inner_where_are_validated_against_outer_and_inner_tables
92
+ assert_raises ArgumentError do
93
+ Select.all.from[:table].where do
94
+ exists(Select.all.from[:inner_table].where do
95
+ table.column1 = not_table.cat
96
+ end)
97
+ end
98
+ end
99
+ end
20
100
  end
data/test/select_test.rb CHANGED
@@ -23,8 +23,7 @@ class SelectTest < Test::Unit::TestCase
23
23
  end
24
24
 
25
25
  def test_select_with_multiple_tables
26
- assert_equal 'select column from bar, foo',
27
- Select[:column].from[:foo, :bar].to_sql
26
+ assert_equal 'select column from bar, foo', Select[:column].from[:foo, :bar].to_sql
28
27
  end
29
28
 
30
29
  def test_order_by
@@ -44,11 +43,19 @@ class SelectTest < Test::Unit::TestCase
44
43
  end
45
44
 
46
45
  def test_table_aliasing
47
- assert_equal 'select * from table1 as foo, table2 as bar', Select.all.from[:table1 => :foo, :table2 => :bar].to_sql
46
+ assert_equal 'select * from table1 foo, table2 bar', Select.all.from[:table1 => :foo, :table2 => :bar].to_sql
47
+ end
48
+
49
+ def test_tables_no_aliasing
50
+ assert_equal 'select * from table1, table2', Select.all.from[:table1, :table2].to_sql
48
51
  end
49
52
 
50
53
  def test_select_all
51
54
  assert_equal 'select *', Select.all.to_sql
52
55
  end
53
56
 
57
+ def test_table_array
58
+ assert_equal [:table1, :table2], Select.all.from[:table1, :table2].instance_variable_get("@tables")
59
+ end
60
+
54
61
  end
data/test/string_test.rb CHANGED
@@ -8,9 +8,4 @@ class StringTest < Test::Unit::TestCase
8
8
  def test_to_sql_gives_quoted_and_escapes_single_quotes
9
9
  assert_equal "'it''s'", "it's".to_sql
10
10
  end
11
-
12
- def test_is_a_where_value_duck
13
- assert_equal true, "foo".respond_to?(:is_not_in)
14
- end
15
-
16
11
  end
data/test/symbol_test.rb CHANGED
@@ -4,9 +4,4 @@ class SymbolTest < Test::Unit::TestCase
4
4
  def test_to_sql_returns_to_s
5
5
  assert_equal 'asdf', :asdf.to_sql
6
6
  end
7
-
8
- def test_is_a_where_value_duck
9
- assert_equal true, :sym.respond_to?(:is_not_in)
10
- end
11
-
12
7
  end
data/test/test_helper.rb CHANGED
@@ -1,2 +1,7 @@
1
1
  require 'test/unit'
2
+ unless File.directory? File.dirname(__FILE__) + '/../vendor/mocha-0.4.0/'
3
+ raise "mocha 4.0 is required to run the test suite. create the 'vendor' directory as a sibling of test and 'gem unpack mocha' in 'vendor'"
4
+ end
5
+ $:.unshift File.dirname(__FILE__) + '/../vendor/mocha-0.4.0/lib/'
6
+ require File.dirname(__FILE__) + '/../vendor/mocha-0.4.0/lib/mocha'
2
7
  require File.dirname(__FILE__) + '/../lib/sqldsl'
@@ -2,108 +2,117 @@ require File.dirname(__FILE__) + '/test_helper'
2
2
 
3
3
  class WhereBuilderTest < Test::Unit::TestCase
4
4
 
5
- def test_single_equal_where_criteria
6
- statement = WhereBuilder.new do
7
- equal :'foo.column1', :'bar.column2'
8
- end
9
- assert_equal ' where foo.column1 = bar.column2', statement.to_sql
5
+ def test_condition_calls_to_sql
6
+ lval, rval = mock, mock
7
+ lval.expects(:to_sql).returns "lval"
8
+ rval.expects(:to_sql).returns "rval"
9
+ where = WhereBuilder.new([], &lambda {})
10
+ where.add_condition(lval, "op", rval)
11
+ assert_equal "lval op rval", where.send(:sql_parts).first
10
12
  end
11
-
12
- def test_less_then_equal_where_criteria
13
- statement = WhereBuilder.new do
14
- column1 <= column2
15
- end
16
- assert_equal " where column1 <= column2", statement.to_sql
13
+
14
+ def test_parenthesis_condition_calls_to_sql
15
+ lval, rval = mock, mock
16
+ lval.expects(:to_sql).returns "lval"
17
+ rval.expects(:to_sql).returns "rval"
18
+ where = WhereBuilder.new([], &lambda {})
19
+ where.add_parenthesis_condition(lval, "op", rval)
20
+ assert_equal "lval op (rval)", where.send(:sql_parts).first
17
21
  end
18
-
19
- def test_less_then_equal_with_table_aliasing_where_criteria
20
- statement = WhereBuilder.new do
21
- table1.column1 <= table2.column2
22
+
23
+ def test_method_missing_for_receive_any_creation
24
+ assert_equal ReceiveAny, WhereBuilder.new([], &lambda {}).missing_method.class
25
+ end
26
+
27
+ def test_method_missing_when_method_call_is_likely_a_mistake
28
+ assert_raises NoMethodError do
29
+ WhereBuilder.new([], &lambda {}).missing_method(:with_args)
22
30
  end
23
- assert_equal " where table1.column1 <= table2.column2", statement.to_sql
24
31
  end
25
32
 
26
- def test_less_then_equal_with_table_aliasing_where_criteria
27
- statement = WhereBuilder.new do
28
- table1.column1 >= table2.column2
33
+ def test_equal
34
+ statement = WhereBuilder.new [] do
35
+ equal :column1, :column2
29
36
  end
30
- assert_equal " where table1.column1 >= table2.column2", statement.to_sql
37
+ assert_equal ' where column1 = column2', statement.to_sql
31
38
  end
32
39
 
33
- def test_equal_with_table_aliasing_where_criteria
34
- statement = WhereBuilder.new do
35
- table1.Column1 = table2.Folumn2
40
+ def test_not_equal
41
+ statement = WhereBuilder.new [] do
42
+ not_equal :column1, :column2
36
43
  end
37
- assert_equal " where table1.Column1 = table2.Folumn2", statement.to_sql
44
+ assert_equal " where column1 <> column2", statement.to_sql
38
45
  end
39
46
 
40
- def test_equal_with_a_numeric
41
- statement = WhereBuilder.new do
42
- table1.Column1 = 1
47
+ def test_is_in_array
48
+ statement = WhereBuilder.new [] do
49
+ is_in :column1, [1,2]
43
50
  end
44
- assert_equal " where table1.Column1 = 1", statement.to_sql
51
+ assert_equal " where column1 in (1, 2)", statement.to_sql
45
52
  end
46
53
 
47
- def test_equal_with_a_string
48
- statement = WhereBuilder.new do
49
- table1.Column1 = "foo"
54
+ def test_is_not_in_where_criteria
55
+ statement = WhereBuilder.new [] do
56
+ is_not_in :column1, [1,2]
50
57
  end
51
- assert_equal " where table1.Column1 = 'foo'", statement.to_sql
58
+ assert_equal ' where column1 not in (1, 2)', statement.to_sql
52
59
  end
53
60
 
54
- def test_single_equal_with_array_where_criteria
55
- statement = WhereBuilder.new do
56
- equal :'foo.column1', ['foo','bar']
61
+ def test_less_than
62
+ statement = WhereBuilder.new [] do
63
+ less_than :column1, :column2
57
64
  end
58
- assert_equal " where foo.column1 in ('foo', 'bar')", statement.to_sql
65
+ assert_equal " where column1 < column2", statement.to_sql
66
+ end
67
+
68
+ def test_less_than_or_equal
69
+ statement = WhereBuilder.new [] do
70
+ less_than_or_equal :column1, :column2
71
+ end
72
+ assert_equal " where column1 <= column2", statement.to_sql
59
73
  end
60
74
 
61
- def test_multiple_equal_with_more_than_one_where_criteria
62
- statement = WhereBuilder.new do
63
- equal :'foo.column1', :'bar.column2'
64
- equal :'foo.column3', :'bar.column5'
75
+ def test_greater_than
76
+ statement = WhereBuilder.new [] do
77
+ greater_than :column1, :column2
65
78
  end
66
- expected = " where foo.column1 = bar.column2 and foo.column3 = bar.column5"
67
- assert_equal expected, statement.to_sql
79
+ assert_equal " where column1 > column2", statement.to_sql
80
+ end
81
+
82
+ def test_greater_than_or_equal
83
+ statement = WhereBuilder.new [] do
84
+ greater_than_or_equal :column1, :column2
85
+ end
86
+ assert_equal " where column1 >= column2", statement.to_sql
68
87
  end
69
88
 
70
- def test_with_literal_where_criteria
71
- statement = WhereBuilder.new do
72
- equal 'foo.column1', :'bar.column2'
73
- equal :'foo.column3', 'bar.column5'
89
+ def test_where_clause_is_built_with_multiple_conditions
90
+ statement = WhereBuilder.new [] do
91
+ equal :column1, :column2
92
+ equal :column3, :column5
74
93
  end
75
- expected = " where 'foo.column1' = bar.column2 and foo.column3 = 'bar.column5'"
94
+ expected = " where column1 = column2 and column3 = column5"
76
95
  assert_equal expected, statement.to_sql
77
96
  end
78
97
 
79
- def test_exists_evaluates_sql_statement_followed
80
- statement = WhereBuilder.new do
98
+ def test_exists_evaluates_sql_statement_argument
99
+ statement = WhereBuilder.new [] do
81
100
  exists Struct.new(:to_sql).new('select foo')
82
101
  end
83
102
  assert_equal ' where exists (select foo)', statement.to_sql
84
103
  end
85
104
 
86
- def test_not_exists_evaluates_sql_statement_followed
87
- statement = WhereBuilder.new do
105
+ def test_not_exists_evaluates_sql_statement_argument
106
+ statement = WhereBuilder.new [] do
88
107
  not_exists Struct.new(:to_sql).new('select foo')
89
108
  end
90
109
  assert_equal ' where not exists (select foo)', statement.to_sql
91
110
  end
92
111
 
93
112
  def test_is_not_null_where_criteria
94
- statement = WhereBuilder.new do
95
- not_null :something
113
+ statement = WhereBuilder.new [] do
114
+ is_not_null Struct.new(:to_sql).new('something')
96
115
  end
97
116
  assert_equal ' where something is not null', statement.to_sql
98
117
  end
99
-
100
- def test_is_not_in_where_criteria
101
- statement = WhereBuilder.new do
102
- :column1.is_not_in do
103
- Select[:shipment_option_id]
104
- end
105
- end
106
- assert_equal ' where column1 not in (select shipment_option_id)', statement.to_sql
107
- end
108
-
109
- end
118
+ end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0
2
+ rubygems_version: 0.8.11
3
3
  specification_version: 1
4
4
  name: sqldsl
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.2.2
7
- date: 2007-03-01 00:00:00 -05:00
6
+ version: 1.3.0
7
+ date: 2007-03-11 00:00:00 -05:00
8
8
  summary: A DSL for creating SQL Statements
9
9
  require_paths:
10
10
  - lib
@@ -25,7 +25,6 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
25
25
  platform: ruby
26
26
  signing_key:
27
27
  cert_chain:
28
- post_install_message:
29
28
  authors:
30
29
  - Jay Fields
31
30
  files:
@@ -35,7 +34,7 @@ files:
35
34
  - lib/hash.rb
36
35
  - lib/insert.rb
37
36
  - lib/numeric.rb
38
- - lib/object.rb
37
+ - lib/or_where_builder.rb
39
38
  - lib/receive_any.rb
40
39
  - lib/select.rb
41
40
  - lib/sql_statement.rb
@@ -45,7 +44,6 @@ files:
45
44
  - lib/time.rb
46
45
  - lib/update.rb
47
46
  - lib/where_builder.rb
48
- - lib/where_value.rb
49
47
  - test/all_tests.rb
50
48
  - test/array_test.rb
51
49
  - test/delete_acceptance_test.rb
@@ -54,7 +52,7 @@ files:
54
52
  - test/insert_acceptance_test.rb
55
53
  - test/insert_test.rb
56
54
  - test/numeric_test.rb
57
- - test/object_test.rb
55
+ - test/receive_any_test.rb
58
56
  - test/select_acceptance_test.rb
59
57
  - test/select_test.rb
60
58
  - test/string_test.rb
@@ -64,7 +62,6 @@ files:
64
62
  - test/update_acceptance_test.rb
65
63
  - test/update_test.rb
66
64
  - test/where_builder_test.rb
67
- - test/where_value_test.rb
68
65
  - rakefile.rb
69
66
  - README
70
67
  test_files:
data/lib/object.rb DELETED
@@ -1,34 +0,0 @@
1
- class Object
2
-
3
- # call-seq: obj.to_sql_equal(any) -> a_string
4
- #
5
- # Returns a string containing the sql equality expression
6
- #
7
- # 10.to_sql_equal(:column1) #=> "column1 = 10"
8
- def to_sql_equal(lval)
9
- sql_expression(lval, "=")
10
- end
11
-
12
- def to_sql_more_than(lval) #:nodoc:
13
- sql_expression(lval, ">")
14
- end
15
-
16
- def to_sql_less_than(lval) #:nodoc:
17
- sql_expression(lval, "<")
18
- end
19
-
20
- def to_sql_less_than_or_equal_to(lval) #:nodoc:
21
- sql_expression(lval, "<=")
22
- end
23
-
24
- def to_sql_more_than_or_equal_to(lval) #:nodoc:
25
- sql_expression(lval, ">=")
26
- end
27
-
28
- protected
29
-
30
- def sql_expression(lval, operator) #:nodoc:
31
- "#{ lval.to_sql } #{operator} #{ self.to_sql }"
32
- end
33
-
34
- end
data/lib/where_value.rb DELETED
@@ -1,8 +0,0 @@
1
- module WhereValue
2
-
3
- def is_not_in &block
4
- builder = eval "self", block.binding
5
- builder.sql_parts << "#{self.to_sql} not in (#{block.call.to_sql})"
6
- end
7
-
8
- end
data/test/object_test.rb DELETED
@@ -1,29 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper'
2
-
3
- class ObjectTest < Test::Unit::TestCase
4
-
5
- def test_to_sql_equal
6
- assert_equal "column1 = foo", foo.to_sql_equal(:column1)
7
- end
8
-
9
- def test_to_sql_more_than
10
- assert_equal "column1 > foo", foo.to_sql_more_than(:column1)
11
- end
12
-
13
- def test_to_sql_less_than
14
- assert_equal "column1 < foo", foo.to_sql_less_than(:column1)
15
- end
16
-
17
- def test_to_sql_less_than_equal
18
- assert_equal "column1 <= foo", foo.to_sql_less_than_or_equal_to(:column1)
19
- end
20
-
21
- def test_to_sql_more_than_equal
22
- assert_equal "column1 >= foo", foo.to_sql_more_than_or_equal_to(:column1)
23
- end
24
-
25
- def foo
26
- Struct.new(:to_sql).new(:foo)
27
- end
28
-
29
- end
@@ -1,22 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper'
2
-
3
- class WhereValueTest < Test::Unit::TestCase
4
-
5
- def test_not_in_sql_statement_with_value
6
- klass = Class.new() do
7
- include WhereValue
8
-
9
- def to_sql
10
- "klass"
11
- end
12
- end
13
-
14
- statement = Select[:foo].where do
15
- klass.new.is_not_in do
16
- "anything"
17
- end
18
- end
19
- assert_equal "select foo where klass not in ('anything')", statement.to_sql
20
- end
21
-
22
- end