sequel_core 1.5.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/CHANGELOG +116 -0
  2. data/COPYING +19 -19
  3. data/README +83 -32
  4. data/Rakefile +9 -20
  5. data/bin/sequel +43 -112
  6. data/doc/cheat_sheet.rdoc +225 -0
  7. data/doc/dataset_filtering.rdoc +257 -0
  8. data/lib/sequel_core/adapters/adapter_skeleton.rb +4 -2
  9. data/lib/sequel_core/adapters/ado.rb +3 -1
  10. data/lib/sequel_core/adapters/db2.rb +4 -2
  11. data/lib/sequel_core/adapters/dbi.rb +127 -113
  12. data/lib/sequel_core/adapters/informix.rb +4 -2
  13. data/lib/sequel_core/adapters/jdbc.rb +5 -3
  14. data/lib/sequel_core/adapters/mysql.rb +112 -46
  15. data/lib/sequel_core/adapters/odbc.rb +5 -7
  16. data/lib/sequel_core/adapters/odbc_mssql.rb +12 -3
  17. data/lib/sequel_core/adapters/openbase.rb +3 -1
  18. data/lib/sequel_core/adapters/oracle.rb +11 -9
  19. data/lib/sequel_core/adapters/postgres.rb +261 -262
  20. data/lib/sequel_core/adapters/sqlite.rb +72 -22
  21. data/lib/sequel_core/connection_pool.rb +140 -73
  22. data/lib/sequel_core/core_ext.rb +201 -66
  23. data/lib/sequel_core/core_sql.rb +123 -153
  24. data/lib/sequel_core/database/schema.rb +156 -0
  25. data/lib/sequel_core/database.rb +321 -338
  26. data/lib/sequel_core/dataset/callback.rb +11 -12
  27. data/lib/sequel_core/dataset/convenience.rb +213 -240
  28. data/lib/sequel_core/dataset/pagination.rb +58 -43
  29. data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +331 -0
  30. data/lib/sequel_core/dataset/query.rb +41 -0
  31. data/lib/sequel_core/dataset/schema.rb +15 -0
  32. data/lib/sequel_core/dataset/sequelizer.rb +41 -373
  33. data/lib/sequel_core/dataset/sql.rb +741 -632
  34. data/lib/sequel_core/dataset.rb +183 -168
  35. data/lib/sequel_core/deprecated.rb +1 -169
  36. data/lib/sequel_core/exceptions.rb +24 -19
  37. data/lib/sequel_core/migration.rb +44 -52
  38. data/lib/sequel_core/object_graph.rb +43 -42
  39. data/lib/sequel_core/pretty_table.rb +71 -76
  40. data/lib/sequel_core/schema/generator.rb +163 -105
  41. data/lib/sequel_core/schema/sql.rb +250 -93
  42. data/lib/sequel_core/schema.rb +2 -8
  43. data/lib/sequel_core/sql.rb +394 -0
  44. data/lib/sequel_core/worker.rb +37 -27
  45. data/lib/sequel_core.rb +99 -45
  46. data/spec/adapters/informix_spec.rb +0 -1
  47. data/spec/adapters/mysql_spec.rb +177 -124
  48. data/spec/adapters/oracle_spec.rb +0 -1
  49. data/spec/adapters/postgres_spec.rb +98 -58
  50. data/spec/adapters/sqlite_spec.rb +45 -4
  51. data/spec/blockless_filters_spec.rb +269 -0
  52. data/spec/connection_pool_spec.rb +21 -18
  53. data/spec/core_ext_spec.rb +169 -19
  54. data/spec/core_sql_spec.rb +56 -49
  55. data/spec/database_spec.rb +78 -17
  56. data/spec/dataset_spec.rb +300 -428
  57. data/spec/migration_spec.rb +1 -1
  58. data/spec/object_graph_spec.rb +5 -11
  59. data/spec/rcov.opts +1 -1
  60. data/spec/schema_generator_spec.rb +16 -4
  61. data/spec/schema_spec.rb +89 -10
  62. data/spec/sequelizer_spec.rb +56 -56
  63. data/spec/spec.opts +0 -5
  64. data/spec/spec_config.rb +7 -0
  65. data/spec/spec_config.rb.example +5 -5
  66. data/spec/spec_helper.rb +6 -0
  67. data/spec/worker_spec.rb +1 -1
  68. metadata +78 -63
@@ -0,0 +1,225 @@
1
+ = Cheat Sheet
2
+
3
+ == Open a database
4
+
5
+ require 'rubygems'
6
+ require 'sequel'
7
+
8
+ DB = Sequel.sqlite 'my_blog.db'
9
+ DB = Sequel('postgres://user:password@localhost/my_db')
10
+ DB = Sequel.mysql 'my_db', :user => 'user', :password => 'password', :host => 'localhost'
11
+ DB = Sequel.ado 'mydb'
12
+
13
+ == Open an SQLite memory database
14
+
15
+ Without a filename argument, the sqlite adapter will setup a new sqlite database in RAM.
16
+
17
+ DB = Sequel.sqlite
18
+
19
+ == Logging SQL statements
20
+
21
+ require 'logger'
22
+ DB = Sequel.sqlite '', :loggers => [Logger.new($stdout)]
23
+ # or
24
+ DB.loggers << Logger.new(...)
25
+
26
+ == Using raw SQL
27
+
28
+ DB << "CREATE TABLE users (name VARCHAR(255) NOT NULL, age INT(3) NOT NULL)"
29
+ DB.fetch("SELECT name FROM users") do |row|
30
+ p r[:name]
31
+ end
32
+ dataset = DB["SELECT age FROM users"]
33
+ dataset.print
34
+ dataset.map(:age)
35
+
36
+ == Create a dataset
37
+
38
+ dataset = DB[:items]
39
+ dataset = DB.dataset.from(:items)
40
+
41
+ == Most dataset methods are chainable
42
+
43
+ dataset = DB[:managers].where(:salary => 5000..10000).order(:name, :department)
44
+ # or
45
+ dataset = DB.query do
46
+ from :managers
47
+ where :salary => 5000..10000
48
+ order :name, :department
49
+ end
50
+
51
+ == Insert rows
52
+
53
+ dataset.insert(:name => 'Sharon', :grade => 50)
54
+ dataset << {:name => 'Sharon', :grade => 50} # same effect as above
55
+
56
+ == Retrieve rows
57
+
58
+ dataset.each {|r| p r}
59
+ dataset.all #=> [{...}, {...}, ...]
60
+ dataset.first
61
+ dataset.order(:name).last # works only for ordered datasets
62
+
63
+ == Update/Delete rows
64
+
65
+ dataset.filter(:active => false).delete
66
+ dataset.filter('price < ?', 100).update(:active => true)
67
+
68
+ == Datasets are Enumerable
69
+
70
+ dataset.map {|r| r[:name]}
71
+ dataset.map(:name) # same effect as above
72
+
73
+ dataset.inject {|sum, r| sum + r[:value]}
74
+
75
+ == Filtering (see also doc/dataset_filtering.rdoc)
76
+
77
+ dataset.filter(:name => 'abc')
78
+ dataset.filter('name = ?', 'abc')
79
+ dataset.filter(:value > 100)
80
+ dataset.exclude(:value <= 100)
81
+
82
+ dataset.filter(:value => 50..100)
83
+ dataset.where((:value >= 50) & (:value <= 100))
84
+
85
+ dataset.where('value IN ?', [50,75,100])
86
+
87
+ # Get the first record that matches a condition
88
+ dataset[:name => 'abc'] # Same as:
89
+ dataset.filter(:name => 'abc').first
90
+
91
+ # Filter using a subquery
92
+ dataset.filter('price > ?', dataset.select('AVG(price) + 100'))
93
+
94
+ === Advanced filtering using ruby expressions without blocks
95
+
96
+ Available as of Sequel 2.0:
97
+
98
+ DB[:items].filter(:price < 100).sql
99
+ #=> "SELECT * FROM items WHERE (price < 100)"
100
+
101
+ DB[:items].filter(:name.like('AL%')).sql
102
+ #=> "SELECT * FROM items WHERE (name LIKE 'AL%')"
103
+
104
+ There's support for nested expressions with AND, OR and NOT:
105
+
106
+ DB[:items].filter((:x > 5) & (:y > 10)).sql
107
+ #=> "SELECT * FROM items WHERE ((x > 5) AND (y > 10))"
108
+
109
+ DB[:items].filter({:x => 1, :y => 2}.sql_or & ~{:z => 3}).sql
110
+ #=> "SELECT * FROM items WHERE (((x = 1) OR (y = 2)) AND (z != 3))"
111
+
112
+ You can use arithmetic operators and specify SQL functions:
113
+
114
+ DB[:items].filter((:x + :y) > :z).sql
115
+ #=> "SELECT * FROM items WHERE ((x + y) > z)"
116
+
117
+ DB[:items].filter(:price < :AVG[:price] + 100).sql
118
+ #=> "SELECT * FROM items WHERE (price < (AVG(price) + 100))"
119
+
120
+ == Ordering
121
+
122
+ dataset.order(:kind)
123
+ dataset.reverse_order(:kind)
124
+ dataset.order(:kind.desc, :name)
125
+
126
+ == Row ranges
127
+
128
+ dataset.limit(30) # LIMIT 30
129
+ dataset.limit(30, 10) # LIMIT 30 OFFSET 10
130
+
131
+ == Pagination
132
+
133
+ paginated = dataset.paginate(1, 10) # first page, 10 rows per page
134
+ paginated.page_count #=> number of pages in dataset
135
+ paginated.current_page #=> 1
136
+ paginated.next_page #=> next page number or nil
137
+ paginated.prev_page #=> previous page number or nil
138
+ paginated.first_page? #=> true if page number = 1
139
+ paginated.last_page? #=> true if page number = page_count
140
+
141
+ == Joins
142
+
143
+ DB[:items].left_outer_join(:categories, :id => :category_id).sql #=>
144
+ "SELECT * FROM items LEFT OUTER JOIN categories ON categories.id = items.category_id"
145
+
146
+ == Summarizing
147
+
148
+ dataset.count #=> record count
149
+ dataset.max(:price)
150
+ dataset.min(:price)
151
+ dataset.avg(:price)
152
+ dataset.sum(:stock)
153
+
154
+ dataset.group(:category).select(:category, :AVG[:price])
155
+
156
+ == SQL Functions / Literals
157
+
158
+ dataset.update(:updated_at => :NOW[])
159
+ dataset.update(:updated_at => 'NOW()'.lit)
160
+
161
+ dataset.update(:updated_at => "DateValue('1/1/2001')".lit)
162
+ dataset.update(:updated_at => :DateValue['1/1/2001'])
163
+
164
+ == Schema Manipulation
165
+
166
+ DB.create_table :items do
167
+ primary_key :id
168
+ text :name, :unique => true, :null => false
169
+ boolean :active, :default => true
170
+ foreign_key :category_id, :categories
171
+
172
+ index :grade
173
+ end
174
+
175
+ DB.drop_table :items
176
+
177
+ DB.create_table :test do
178
+ varchar :zipcode, :size => 10
179
+ enum :system, :elements => ['mac', 'linux', 'windows']
180
+ end
181
+
182
+ == Aliasing
183
+
184
+ DB[:items].select(:name.as(:item_name))
185
+ DB[:items].select(:name => :item_name)
186
+ DB[:items].select(:name___item_name)
187
+ DB[:items___items_table].select(:items_table__name___item_name)
188
+ # => "SELECT items_table.name AS item_name FROM items AS items_table"
189
+
190
+ == Transactions
191
+
192
+ DB.transaction do
193
+ dataset << {:first_name => 'Inigo', :last_name => 'Montoya'}
194
+ dataset << {:first_name => 'Farm', :last_name => 'Boy'}
195
+ end # Either both are inserted or neither are inserted
196
+
197
+ Database#transaction is re-entrant:
198
+
199
+ DB.transaction do # BEGIN issued only here
200
+ DB.transaction
201
+ dataset << {:first_name => 'Inigo', :last_name => 'Montoya'}
202
+ end
203
+ end # COMMIT issued only here
204
+
205
+ Transactions are aborted if an error is raised:
206
+
207
+ DB.transaction do
208
+ raise "some error occurred"
209
+ end # ROLLBACK issued and the error is re-raised
210
+
211
+ Transactions can also be aborted by raising Sequel::Error::Rollback:
212
+
213
+ DB.transaction do
214
+ raise(Sequel::Error::Rollback) if something_bad_happened
215
+ end # ROLLBACK issued and no error raised
216
+
217
+ Miscellaneous:
218
+
219
+ dataset.sql #=> "SELECT * FROM items"
220
+ dataset.delete_sql #=> "DELETE FROM items"
221
+ dataset.where(:name => 'sequel').exists #=> "EXISTS ( SELECT 1 FROM items WHERE name = 'sequel' )"
222
+ dataset.print #=> pretty table print to $stdout
223
+ dataset.columns #=> array of columns in the result set, does a SELECT
224
+ DB.schema_for_table(:items) => [[:id, {:type=>:integer, ...}], [:name, {:type=>:string, ...}], ...]
225
+ # Works on PostgreSQL, MySQL, SQLite, and possibly elsewhere
@@ -0,0 +1,257 @@
1
+ = Dataset Filtering
2
+
3
+ Sequel offers unparalleled flexibility when it comes to filtering records. You can specify your conditions as a custom string, as a string with parameters, as a hash of values to compare against, or as ruby code that Sequel translates into SQL expressions.
4
+
5
+ == Filtering using a custom filter string
6
+
7
+ If you do not wish to lose control over your SQL WHERE clauses, you can just supply it to the dataset's #filter method:
8
+
9
+ items.filter('x < 10').sql
10
+ #=> "SELECT * FROM items WHERE x < 10"
11
+
12
+ In order to prevent SQL injection, you can replace literal values with question marks and supply the values as additional arguments:
13
+
14
+ items.filter('category = ?', 'ruby').sql
15
+ #=> "SELECT * FROM items WHERE category = 'ruby'"
16
+
17
+ == An aside: column references in Sequel
18
+
19
+ Sequel expects column names to be specified using symbols. In addition, tuples always use symbols as their keys. This allows you to freely mix literal values and column references. For example, the two following lines produce equivalent SQL:
20
+
21
+ items.filter(:x => 1) #=> "SELECT * FROM items WHERE (x = 1)"
22
+ items.filter(1 => :x) #=> "SELECT * FROM items WHERE (1 = x)"
23
+
24
+ === Qualifying column names
25
+
26
+ Column references can be qualified by using the double underscore special notation :table__column:
27
+
28
+ items.literal(:items__price) #=> "items.price"
29
+
30
+ === Column aliases
31
+
32
+ You can also alias columns by using the triple undersecore special notation :column___alias or :table__column___alias:
33
+
34
+ items.literal(:price___p) #=> "price AS p"
35
+ items.literal(:items__price___p) #=> "items.price AS p"
36
+
37
+ Another way to alias columns is to use the #AS method:
38
+
39
+ items.literal(:price.as(:p)) #=> "price AS p"
40
+
41
+ === Specifying SQL functions
42
+
43
+ Sequel also allows you to specify functions by using the Symbol#[] method:
44
+
45
+ items.literal(:avg[:price]) #=> "avg(price)"
46
+
47
+ == Filtering using a hash
48
+
49
+ If you just need to compare records against values, you can supply a hash:
50
+
51
+ items.filter(:category => 'ruby').sql
52
+ #=> "SELECT * FROM items WHERE (category = 'ruby')"
53
+
54
+ Sequel can check for null values:
55
+
56
+ items.filter(:category => nil).sql
57
+ #=> "SELECT * FROM items WHERE (category IS NULL)"
58
+
59
+ Or compare two columns:
60
+
61
+ items.filter(:x => :some_table__y).sql
62
+ #=> "SELECT * FROM items WHERE (x = some_table.y)"
63
+
64
+ And also compare against multiple values:
65
+
66
+ items.filter(:category => ['ruby', 'perl']).sql
67
+ #=> "SELECT * FROM items WHERE (category IN ('ruby', 'perl'))"
68
+
69
+ Ranges (both inclusive and exclusive) can also be used:
70
+
71
+ items.filter(:price => 100..200).sql
72
+ #=> "SELECT * FROM items WHERE (price >= 100 AND price <= 200)"
73
+
74
+ items.filter(:price => 100...200).sql
75
+ #=> "SELECT * FROM items WHERE (price >= 100 AND price < 200)"
76
+
77
+ == Filtering using expressions
78
+
79
+ New in Sequel 2.0 is the ability to use ruby expressions directly in the call to filter, without using a block:
80
+
81
+ items.filter(:price < 100).sql
82
+ #=> "SELECT * FROM items WHERE (price < 100)
83
+
84
+ This works for the standard inequality and arithmetic operators:
85
+
86
+ items.filter(:price + 100 < 200).sql
87
+ #=> "SELECT * FROM items WHERE ((price + 100) < 200)
88
+
89
+ items.filter(:price - 100 > 200).sql
90
+ #=> "SELECT * FROM items WHERE ((price - 100) > 200)
91
+
92
+ items.filter(:price * 100 <= 200).sql
93
+ #=> "SELECT * FROM items WHERE ((price * 100) <= 200)
94
+
95
+ items.filter(:price / 100 >= 200).sql
96
+ #=> "SELECT * FROM items WHERE ((price / 100) >= 200)
97
+
98
+ You use the overloaded bitwise and (&) and or (|) operators to combine expressions:
99
+
100
+ items.filter((:price + 100 < 200) & (:price * 100 <= 200)).sql
101
+ #=> "SELECT * FROM items WHERE (((price + 100) < 200) AND ((price * 100) <= 200))
102
+
103
+ items.filter((:price - 100 > 200) | (:price / 100 >= 200)).sql
104
+ #=> "SELECT * FROM items WHERE (((price - 100) > 200) OR ((price / 100) >= 200))
105
+
106
+ To filter by equality, you use the standard hash, which can be combined with other operators:
107
+
108
+ items.filter({:category => 'ruby'} & (:price + 100 < 200)).sql
109
+ #=> "SELECT * FROM items WHERE ((category = 'ruby') AND ((price + 100) < 200))"
110
+
111
+ This works with other hash values, such as arrays and ranges:
112
+
113
+ items.filter({:category => ['ruby', 'other']} | (:price - 100 > 200)).sql
114
+ #=> "SELECT * FROM items WHERE ((category IN ('ruby', 'other')) OR ((price - 100) <= 200))"
115
+
116
+ items.filter({:price == (100..200)} & :active).sql
117
+ #=> "SELECT * FROM items WHERE ((price >= 100 AND price <= 200) AND active)"
118
+
119
+ === Negating conditions
120
+
121
+ You can use the negation operator (~) in most cases:
122
+
123
+ items.filter(~{:category => 'ruby'}).sql
124
+ #=> "SELECT * FROM items WHERE (category != 'ruby')"
125
+
126
+ items.filter {~:active}.sql
127
+ #=> "SELECT * FROM items WHERE NOT active"
128
+
129
+ items.filter(~(:price / 100 >= 200)).sql
130
+ #=> "SELECT * FROM items WHERE ((price / 100) < 200)
131
+
132
+ === Comparing against column references
133
+
134
+ You can also compare against other columns:
135
+
136
+ items.filter(:credit > :debit).sql
137
+ #=> "SELECT * FROM items WHERE (credit > debit)
138
+
139
+ Or against SQL functions:
140
+
141
+ items.filter(:price < :max[:price] + 100).sql
142
+ #=> "SELECT * FROM items WHERE (price < (max(price) + 100))"
143
+
144
+ == String search functions
145
+
146
+ You can search SQL strings using the #like method:
147
+
148
+ items.filter(:name.like('Acme%').sql
149
+ #=> "SELECT * FROM items WHERE (name LIKE 'Acme%')"
150
+
151
+ You can specify a Regexp as a like argument, but this will probably only work
152
+ on PostgreSQL and MySQL:
153
+
154
+ items.filter(:name.like(/Acme.*/).sql
155
+ #=> "SELECT * FROM items WHERE (name ~ 'Acme.*')"
156
+
157
+ Like can also take more than one argument:
158
+
159
+ items.filter(:name.like('Acme%', /Beta.*/).sql
160
+ #=> "SELECT * FROM items WHERE ((name LIKE 'Acme%') OR (name ~ 'Beta.*'))"
161
+
162
+ == String concatenation
163
+
164
+ You can concatenate SQL strings using Array#sql_string_join:
165
+
166
+ items.filter([:name, :comment].sql_string_join.like('%acme%').sql
167
+ #=> "SELECT * FROM items WHERE ((name || comment) LIKE 'Acme%')"
168
+
169
+ Array#sql_string_join also takes a join argument:
170
+
171
+ items.filter([:name, :comment].sql_string_join(' ').like('%acme%').sql
172
+ #=> "SELECT * FROM items WHERE ((name || ' ' || comment) LIKE 'Acme%')"
173
+
174
+ == Filtering using expressions with blocks
175
+
176
+ Most SQL expressions that you can can create with expressions you can also express inside blocks. This was previously the only way to specify expressions using ruby code. Filtering with blocks requires that you install ParseTree, ruby2ruby, and their dependencies. It's slower than using the equivalent expression without a block, and the syntax inside the block is different in some cases. Because it requires ParseTree, it can only be used with MRI (Matz's Ruby Interpreter) 1.8.*, as ParseTree doesn't run on any other ruby implementation (blockless filters should work on other ruby implementations).
177
+
178
+ In general, filtering with a block should only be used with legacy code. While it is not officially deprecated, usage of blocks when filtering is discouraged.
179
+
180
+ To filter with a block, supply a block to filter with the appropriate ruby code:
181
+
182
+ items.filter{:price < 100}.sql
183
+ #=> "SELECT * FROM items WHERE (price < 100)
184
+
185
+ Sequel is smart enough to literalize values correctly, even if you compare against arrays or ranges:
186
+
187
+ items.filter{:category == 'ruby'}.sql
188
+ #=> "SELECT * FROM items WHERE (category = 'ruby')"
189
+
190
+ items.filter{:category == ['ruby', 'other']}.sql
191
+ #=> "SELECT * FROM items WHERE (category IN ('ruby', 'other'))"
192
+
193
+ items.filter{:price == (100..200)}.sql
194
+ #=> "SELECT * FROM items WHERE (price >= 100 AND price <= 200)"
195
+
196
+ === Negating conditions
197
+
198
+ You can use the negation operator (!) anywhere:
199
+
200
+ items.filter{:category != 'ruby'}.sql
201
+ #=> "SELECT * FROM items WHERE NOT (category = 'ruby')"
202
+
203
+ items.filter{!:active}.sql
204
+ #=> "SELECT * FROM items WHERE (active = 'f')"
205
+
206
+ === Comparing against column references
207
+
208
+ You can also compare against other columns:
209
+
210
+ items.filter{:credit > :debit}.sql
211
+ #=> "SELECT * FROM items WHERE (credit > debit)
212
+
213
+ Or against SQL functions:
214
+
215
+ items.filter{:price < :max[:price] + 100}.sql
216
+ #=> "SELECT * FROM items WHERE (price < (max(price) + 100))"
217
+
218
+ === Concatenating conditions with logical operators
219
+
220
+ Expressions can be nested and combined using logical operators:
221
+
222
+ items.filter{(:price < 100 && :age < 27) || :category == 'ruby'}.sql
223
+ #=> "SELECT * FROM items WHERE (((price < 100) AND (age < 27)) OR (category = 'ruby'))"
224
+
225
+ Another way to concatenate conditions is to specify each condition as a separate statement:
226
+
227
+ items.filter do
228
+ :price < 100
229
+ :category == 'ruby'
230
+ end.sql
231
+ #=> "SELECT * FROM items WHERE ((price < 100) AND (category = 'ruby'))"
232
+
233
+ === Special methods
234
+
235
+ Inside blocks, Sequel recognizes the special methods nil/nil?, in/in? and like/like?:
236
+
237
+ items.filter{:price.nil?}.sql
238
+ #=> "SELECT * FROM items WHERE (price IS NULL)"
239
+
240
+ items.filter{:category.in ['ruby', 'other']}.sql
241
+ #=> "SELECT * FROM items WHERE (category IN ('ruby', 'other'))"
242
+
243
+ items.filter{:price.in 100..200}.sql
244
+ #=> "SELECT * FROM items WHERE (price >= 100 AND price <= 200)"
245
+
246
+ items.filter{:category.like 'ruby%'}.sql
247
+ #=> "SELECT * FROM items WHERE (category LIKE 'ruby%')"
248
+
249
+ == Filtering using sub-queries
250
+
251
+ One of the best features of Sequel is the ability to use datasets as sub-queries. Sub-queries can be very useful for filtering records, and many times provide a simpler alternative to table joins. Sub-queries can be used in all forms of filters:
252
+
253
+ refs = consumer_refs.filter(:logged_in => true).select(:consumer_id)
254
+ consumers.filter(:id => refs).sql
255
+ #=> "SELECT * FROM consumers WHERE (id IN (SELECT consumer_id FROM consumer_refs WHERE (logged_in = 't')))"
256
+
257
+ Note that if you compare against a sub-query, you must select a single column in the sub-query.
@@ -18,7 +18,7 @@ module Sequel
18
18
  end
19
19
 
20
20
  def execute(sql)
21
- @logger.info(sql) if @logger
21
+ log_info(sql)
22
22
  @pool.hold {|conn| conn.exec(sql)}
23
23
  end
24
24
 
@@ -30,6 +30,8 @@ module Sequel
30
30
  case v
31
31
  when Time
32
32
  literal(v.iso8601)
33
+ when Date, DateTime
34
+ literal(v.to_s)
33
35
  else
34
36
  super
35
37
  end
@@ -65,4 +67,4 @@ module Sequel
65
67
  end
66
68
  end
67
69
  end
68
- end
70
+ end
@@ -36,7 +36,7 @@ module Sequel
36
36
  end
37
37
 
38
38
  def execute(sql)
39
- @logger.info(sql) if @logger
39
+ log_info(sql)
40
40
  @pool.hold {|conn| conn.Execute(sql)}
41
41
  end
42
42
 
@@ -48,6 +48,8 @@ module Sequel
48
48
  case v
49
49
  when Time
50
50
  literal(v.iso8601)
51
+ when Date, DateTime
52
+ literal(v.to_s)
51
53
  else
52
54
  super
53
55
  end
@@ -54,7 +54,7 @@ module Sequel
54
54
  end
55
55
 
56
56
  def execute(sql, &block)
57
- @logger.info(sql) if @logger
57
+ log_info(sql)
58
58
  @pool.hold do |conn|
59
59
  rc, sth = SQLAllocHandle(SQL_HANDLE_STMT, @handle)
60
60
  check_error(rc, "Could not allocate statement")
@@ -82,6 +82,8 @@ module Sequel
82
82
  case v
83
83
  when Time
84
84
  literal(v.iso8601)
85
+ when Date, DateTime
86
+ literal(v.to_s)
85
87
  else
86
88
  super
87
89
  end
@@ -155,4 +157,4 @@ module Sequel
155
157
  end
156
158
  end
157
159
  end
158
- end
160
+ end