sequel 4.40.0 → 4.41.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +30 -0
  3. data/Rakefile +6 -3
  4. data/doc/association_basics.rdoc +3 -3
  5. data/doc/opening_databases.rdoc +3 -3
  6. data/doc/release_notes/4.41.0.txt +77 -0
  7. data/doc/schema_modification.rdoc +11 -11
  8. data/lib/sequel/adapters/ado.rb +137 -9
  9. data/lib/sequel/adapters/ado/mssql.rb +1 -1
  10. data/lib/sequel/adapters/jdbc.rb +1 -1
  11. data/lib/sequel/adapters/mysql2.rb +0 -1
  12. data/lib/sequel/adapters/shared/db2.rb +30 -10
  13. data/lib/sequel/adapters/shared/mssql.rb +11 -6
  14. data/lib/sequel/database/query.rb +3 -6
  15. data/lib/sequel/database/schema_generator.rb +7 -1
  16. data/lib/sequel/database/schema_methods.rb +0 -6
  17. data/lib/sequel/dataset/actions.rb +4 -4
  18. data/lib/sequel/dataset/graph.rb +3 -2
  19. data/lib/sequel/dataset/misc.rb +23 -0
  20. data/lib/sequel/dataset/mutation.rb +15 -14
  21. data/lib/sequel/dataset/query.rb +25 -5
  22. data/lib/sequel/extensions/constraint_validations.rb +1 -3
  23. data/lib/sequel/extensions/sql_comments.rb +6 -1
  24. data/lib/sequel/model/associations.rb +7 -1
  25. data/lib/sequel/model/base.rb +1 -1
  26. data/lib/sequel/plugins/class_table_inheritance.rb +6 -6
  27. data/lib/sequel/plugins/hook_class_methods.rb +2 -2
  28. data/lib/sequel/plugins/json_serializer.rb +29 -7
  29. data/lib/sequel/version.rb +1 -1
  30. data/spec/adapters/firebird_spec.rb +2 -8
  31. data/spec/adapters/mssql_spec.rb +12 -12
  32. data/spec/adapters/mysql_spec.rb +11 -11
  33. data/spec/adapters/postgres_spec.rb +8 -9
  34. data/spec/adapters/spec_helper.rb +1 -0
  35. data/spec/adapters/sqlite_spec.rb +1 -3
  36. data/spec/core/database_spec.rb +3 -2
  37. data/spec/core/dataset_spec.rb +66 -22
  38. data/spec/core/expression_filters_spec.rb +4 -0
  39. data/spec/core/mock_adapter_spec.rb +1 -1
  40. data/spec/core/schema_generator_spec.rb +1 -1
  41. data/spec/core/schema_spec.rb +10 -1
  42. data/spec/core/spec_helper.rb +1 -0
  43. data/spec/extensions/class_table_inheritance_spec.rb +3 -0
  44. data/spec/extensions/connection_expiration_spec.rb +1 -1
  45. data/spec/extensions/graph_each_spec.rb +6 -0
  46. data/spec/extensions/hook_class_methods_spec.rb +46 -0
  47. data/spec/extensions/json_serializer_spec.rb +8 -3
  48. data/spec/extensions/set_overrides_spec.rb +4 -0
  49. data/spec/extensions/single_table_inheritance_spec.rb +2 -2
  50. data/spec/extensions/spec_helper.rb +1 -0
  51. data/spec/extensions/string_agg_spec.rb +4 -0
  52. data/spec/extensions/uuid_spec.rb +1 -2
  53. data/spec/integration/associations_test.rb +14 -0
  54. data/spec/integration/dataset_test.rb +17 -22
  55. data/spec/integration/schema_test.rb +3 -3
  56. data/spec/integration/spec_helper.rb +1 -0
  57. data/spec/integration/type_test.rb +1 -7
  58. data/spec/model/associations_spec.rb +26 -1
  59. data/spec/model/model_spec.rb +7 -1
  60. data/spec/model/spec_helper.rb +2 -0
  61. data/spec/sequel_warning.rb +4 -0
  62. metadata +6 -3
@@ -13,7 +13,7 @@ module Sequel
13
13
  #
14
14
  # album = Album[1]
15
15
  # album.to_json
16
- # # => '{"json_class"=>"Album","id"=>1,"name"=>"RF","artist_id"=>2}'
16
+ # # => '{"id"=>1,"name"=>"RF","artist_id"=>2}'
17
17
  #
18
18
  # In addition, you can provide options to control the JSON output:
19
19
  #
@@ -22,16 +22,23 @@ module Sequel
22
22
  # # => '{"json_class"="Album","name"=>"RF"}'
23
23
  #
24
24
  # album.to_json(:include=>:artist)
25
- # # => '{"json_class":"Album","id":1,"name":"RF","artist_id":2,
26
- # # "artist":{"json_class":"Artist","id":2,"name":"YJM"}}'
25
+ # # => '{"id":1,"name":"RF","artist_id":2,
26
+ # # "artist":{"id":2,"name":"YJM"}}'
27
27
  #
28
28
  # You can use a hash value with <tt>:include</tt> to pass options
29
29
  # to associations:
30
30
  #
31
31
  # album.to_json(:include=>{:artist=>{:only=>:name}})
32
- # # => '{"json_class":"Album","id":1,"name":"RF","artist_id":2,
33
- # # "artist":{"json_class":"Artist","name":"YJM"}}'
32
+ # # => '{"id":1,"name":"RF","artist_id":2,
33
+ # # "artist":{"name":"YJM"}}'
34
34
  #
35
+ # You can specify a name for a given association by passing <tt>:name</tt>
36
+ # to the <tt>:include</tt> hash
37
+ #
38
+ # album.to_json(:include=>{Sequel.as(:artist, :singer)=>{:only=>:name}})
39
+ # # => '{"id":1,"name":"RF","artist_id":2,
40
+ # # "singer":{"name":"YJM"}}'
41
+ #
35
42
  # You can specify the <tt>:root</tt> option to nest the JSON under the
36
43
  # name of the model:
37
44
  #
@@ -299,6 +306,13 @@ module Sequel
299
306
  if inc = opts[:include]
300
307
  if inc.is_a?(Hash)
301
308
  inc.each do |k, v|
309
+ if k.is_a?(Sequel::SQL::AliasedExpression)
310
+ key_name = k.aliaz.to_s
311
+ k = k.expression
312
+ else
313
+ key_name = k.to_s
314
+ end
315
+
302
316
  v = v.empty? ? [] : [v]
303
317
 
304
318
  objs = send(k)
@@ -309,14 +323,22 @@ module Sequel
309
323
  objs.is_a?(Array)
310
324
  end
311
325
 
312
- h[k.to_s] = if is_array
326
+ h[key_name] = if is_array
313
327
  objs.map{|obj| Literal.new(Sequel.object_to_json(obj, *v))}
314
328
  else
315
329
  Literal.new(Sequel.object_to_json(objs, *v))
316
330
  end
317
331
  end
318
332
  else
319
- Array(inc).each{|c| h[c.to_s] = send(c)}
333
+ Array(inc).each do |c|
334
+ if c.is_a?(Sequel::SQL::AliasedExpression)
335
+ key_name = c.aliaz.to_s
336
+ c = c.expression
337
+ else
338
+ key_name = c.to_s
339
+ end
340
+ h[key_name] = send(c)
341
+ end
320
342
  end
321
343
  end
322
344
 
@@ -5,7 +5,7 @@ module Sequel
5
5
  MAJOR = 4
6
6
  # The minor version of Sequel. Bumped for every non-patch level
7
7
  # release, generally around once a month.
8
- MINOR = 40
8
+ MINOR = 41
9
9
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
10
10
  # releases that fix regressions from previous versions.
11
11
  TINY = 0
@@ -58,9 +58,8 @@ end
58
58
 
59
59
  describe "A Firebird dataset" do
60
60
  before do
61
- @d = DB[:test]
62
- @d.delete # remove all records
63
- @d.quote_identifiers = true
61
+ @d = DB[:test].with_quote_identifiers(true)
62
+ @d.delete
64
63
  end
65
64
 
66
65
  it "should return the correct record count" do
@@ -90,8 +89,6 @@ describe "A Firebird dataset" do
90
89
  @d << {:name => 'def', :val => 789}
91
90
  @d.filter(:name => 'abc').update(:val => 530)
92
91
 
93
- # the third record should stay the same
94
- # floating-point precision bullshit
95
92
  @d[:name => 'def'][:val].must_equal 789
96
93
  @d.filter(:val => 530).count.must_equal 2
97
94
  end
@@ -112,7 +109,6 @@ describe "A Firebird dataset" do
112
109
  end
113
110
 
114
111
  it "should quote columns and tables using double quotes if quoting identifiers" do
115
- @d.quote_identifiers = true
116
112
  @d.select(:name).sql.must_equal \
117
113
  'SELECT "NAME" FROM "TEST"'
118
114
 
@@ -157,7 +153,6 @@ describe "A Firebird dataset" do
157
153
  end
158
154
 
159
155
  it "should quote fields correctly when reversing the order if quoting identifiers" do
160
- @d.quote_identifiers = true
161
156
  @d.reverse_order(:name).sql.must_equal \
162
157
  'SELECT * FROM "TEST" ORDER BY "NAME" DESC'
163
158
 
@@ -220,7 +215,6 @@ describe "A Firebird dataset" do
220
215
 
221
216
  it "should quote and upcase reserved keywords" do
222
217
  @d = DB[:testing]
223
- @d.quote_identifiers = true
224
218
  @d.select(:select).sql.must_equal \
225
219
  'SELECT "SELECT" FROM "TESTING"'
226
220
  end
@@ -247,7 +247,7 @@ describe "Offset support" do
247
247
  @db.create_table!(:i){Integer :id; Integer :parent_id}
248
248
  @ds = @db[:i].order(:id)
249
249
  @hs = []
250
- @ds.row_proc = proc{|r| @hs << r.dup; r[:id] *= 2; r[:parent_id] *= 3; r}
250
+ @ds = @ds.with_row_proc(proc{|r| @hs << r.dup; r[:id] *= 2; r[:parent_id] *= 3; r})
251
251
  @ds.import [:id, :parent_id], [[1,nil],[2,nil],[3,1],[4,1],[5,3],[6,5]]
252
252
  end
253
253
  after do
@@ -356,7 +356,9 @@ describe "MSSSQL::Dataset#insert" do
356
356
  end
357
357
 
358
358
  it "should have insert_select return nil if the server version is not 2005+" do
359
- def @ds.server_version() 8000760 end
359
+ @ds = @ds.with_extend(Module.new do
360
+ def server_version() 8000760 end
361
+ end)
360
362
  @ds.insert_select(:value=>10).must_equal nil
361
363
  end
362
364
 
@@ -424,20 +426,16 @@ describe "A MSSQL database" do
424
426
  end
425
427
 
426
428
  describe "MSSQL::Database#rename_table" do
427
- after do
428
- DB.drop_table?(:foo)
429
- end
430
-
431
429
  it "should work on non-schema bound tables which need escaping" do
432
430
  DB.quote_identifiers = true
433
431
  DB.create_table! :'foo bar' do
434
432
  text :name
435
433
  end
436
- DB.drop_table? :foo
437
434
  DB.rename_table 'foo bar', 'foo'
435
+ DB.drop_table :foo
438
436
  end
439
437
 
440
- it "should work on schema bound tables" do
438
+ it "should work on schema bound tables within the same schema" do
441
439
  DB.execute(<<-SQL)
442
440
  IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = 'MY')
443
441
  EXECUTE sp_executesql N'create schema MY'
@@ -447,6 +445,7 @@ describe "MSSQL::Database#rename_table" do
447
445
  end
448
446
  DB.rename_table Sequel[:MY][:foo], Sequel[:MY][:bar]
449
447
  DB.rename_table Sequel[:MY][:bar], :foo
448
+ DB.drop_table Sequel[:MY][:foo]
450
449
  end
451
450
  end
452
451
 
@@ -488,10 +487,11 @@ describe "MSSQL::Database#mssql_unicode_strings = false" do
488
487
  DB.create_table!(:items){String :name}
489
488
  ds = DB[:items]
490
489
  ds.mssql_unicode_strings.must_equal false
491
- ds.mssql_unicode_strings = true
492
- ds.mssql_unicode_strings.must_equal true
493
- ds.insert(:name=>'foo')
494
- ds.select_map(:name).must_equal ['foo']
490
+ ds1 = ds.with_mssql_unicode_strings(true)
491
+ ds.mssql_unicode_strings.must_equal false
492
+ ds1.mssql_unicode_strings.must_equal true
493
+ ds1.insert(:name=>'foo')
494
+ ds1.select_map(:name).must_equal ['foo']
495
495
  end
496
496
  end
497
497
 
@@ -150,9 +150,10 @@ if [:mysql, :mysql2].include?(DB.adapter_scheme)
150
150
 
151
151
  it "should allow disabling the conversion on a per-dataset basis" do
152
152
  @db.convert_tinyint_to_bool = true
153
- ds = @ds.clone
154
- def ds.cast_tinyint_integer?(f) true end #mysql
155
- def ds.convert_tinyint_to_bool?() false end #mysql2
153
+ ds = @ds.with_extend(Module.new do
154
+ def cast_tinyint_integer?(f) true end #mysql
155
+ def convert_tinyint_to_bool?() false end #mysql2
156
+ end)
156
157
  ds.delete
157
158
  ds << {:b=>true, :i=>10}
158
159
  ds.all.must_equal [{:b=>1, :i=>10}]
@@ -172,7 +173,7 @@ describe "A MySQL dataset" do
172
173
  end
173
174
 
174
175
  it "should quote columns and tables using back-ticks if quoting identifiers" do
175
- @d.quote_identifiers = true
176
+ @d = @d.with_quote_identifiers(true)
176
177
  @d.select(:name).sql.must_equal 'SELECT `name` FROM `items`'
177
178
  @d.select(Sequel.lit('COUNT(*)')).sql.must_equal 'SELECT COUNT(*) FROM `items`'
178
179
  @d.select(Sequel.function(:max, :value)).sql.must_equal 'SELECT max(`value`) FROM `items`'
@@ -190,7 +191,7 @@ describe "A MySQL dataset" do
190
191
  end
191
192
 
192
193
  it "should quote fields correctly when reversing the order" do
193
- @d.quote_identifiers = true
194
+ @d = @d.with_quote_identifiers(true)
194
195
  @d.reverse_order(:name).sql.must_equal 'SELECT * FROM `items` ORDER BY `name` DESC'
195
196
  @d.reverse_order(Sequel.desc(:name)).sql.must_equal 'SELECT * FROM `items` ORDER BY `name` ASC'
196
197
  @d.reverse_order(:name, Sequel.desc(:test)).sql.must_equal 'SELECT * FROM `items` ORDER BY `name` DESC, `test` ASC'
@@ -242,7 +243,7 @@ describe "MySQL datasets" do
242
243
  end
243
244
 
244
245
  it "should correctly quote column references" do
245
- @d.quote_identifiers = true
246
+ @d = @d.with_quote_identifiers(true)
246
247
  market = 'ICE'
247
248
  ack_stamp = Time.now - 15 * 60 # 15 minutes ago
248
249
  @d.select(:market, Sequel.function(:minute, Sequel.function(:from_unixtime, :ack)).as(:minute)).
@@ -321,8 +322,7 @@ describe "Joined MySQL dataset" do
321
322
  end
322
323
 
323
324
  it "should quote fields correctly" do
324
- @ds.quote_identifiers = true
325
- @ds.join(:attributes, :node_id => :id).sql.must_equal "SELECT * FROM `nodes` INNER JOIN `attributes` ON (`attributes`.`node_id` = `nodes`.`id`)"
325
+ @ds.with_quote_identifiers(true).join(:attributes, :node_id => :id).sql.must_equal "SELECT * FROM `nodes` INNER JOIN `attributes` ON (`attributes`.`node_id` = `nodes`.`id`)"
326
326
  end
327
327
 
328
328
  it "should put a having clause before an order by clause" do
@@ -1168,7 +1168,7 @@ if DB.adapter_scheme == :mysql or DB.adapter_scheme == :jdbc or DB.adapter_schem
1168
1168
  @d.call_sproc(:select, :test_sproc, 3).must_equal []
1169
1169
  @d.insert(:value=>1)
1170
1170
  @d.call_sproc(:select, :test_sproc, 4).must_equal [{:id=>nil, :value=>1, :b=>4}]
1171
- @d.row_proc = proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r}
1171
+ @d = @d.with_row_proc(proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r})
1172
1172
  @d.call_sproc(:select, :test_sproc, 3).must_equal [{:id=>nil, :value=>2, :b=>6}]
1173
1173
  end
1174
1174
 
@@ -1179,7 +1179,7 @@ if DB.adapter_scheme == :mysql or DB.adapter_scheme == :jdbc or DB.adapter_schem
1179
1179
  @d.call_sproc(:select, :test_sproc, 3, 4).must_equal []
1180
1180
  @d.insert(:value=>1)
1181
1181
  @d.call_sproc(:select, :test_sproc, 4, 5).must_equal [{:id=>nil, :value=>1, :b=>4, :d=>5}]
1182
- @d.row_proc = proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r}
1182
+ @d = @d.with_row_proc(proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r})
1183
1183
  @d.call_sproc(:select, :test_sproc, 3, 4).must_equal [{:id=>nil, :value=>2, :b=>6, :d => 8}]
1184
1184
  end
1185
1185
  end
@@ -1259,7 +1259,7 @@ if DB.adapter_scheme == :mysql
1259
1259
  end
1260
1260
 
1261
1261
  it "should have regular row_procs work when splitting multiple result sets" do
1262
- @ds.row_proc = proc{|x| x[x.keys.first] *= 2; x}
1262
+ @ds = @ds.with_row_proc(proc{|x| x[x.keys.first] *= 2; x})
1263
1263
  @ds.split_multiple_result_sets.all.must_equal [[{:a=>20}, {:a=>30}], [{:b=>40}, {:b=>50}]]
1264
1264
  end
1265
1265
 
@@ -964,13 +964,10 @@ describe "A PostgreSQL database" do
964
964
  @db[:posts].order(:a).map(:a).must_equal [1, 2, 10, 20, 21]
965
965
  end
966
966
 
967
- it "should support specifying Integer/Bignum/Fixnum types in primary keys and have them be auto incrementing" do
967
+ it "should support specifying Integer/Bignum types in primary keys and have them be auto incrementing" do
968
968
  @db.create_table(:posts){primary_key :a, :type=>Integer}
969
969
  @db[:posts].insert.must_equal 1
970
970
  @db[:posts].insert.must_equal 2
971
- @db.create_table!(:posts){primary_key :a, :type=>Fixnum}
972
- @db[:posts].insert.must_equal 1
973
- @db[:posts].insert.must_equal 2
974
971
  @db.create_table!(:posts){primary_key :a, :type=>:Bignum}
975
972
  @db[:posts].insert.must_equal 1
976
973
  @db[:posts].insert.must_equal 2
@@ -1730,11 +1727,13 @@ if DB.adapter_scheme == :postgres
1730
1727
  end
1731
1728
 
1732
1729
  it "should handle returning inside block" do
1733
- def @ds.check_return
1734
- use_cursor.each{|r| return}
1735
- end
1736
- @ds.check_return
1737
- @ds.all.must_equal @ds.use_cursor.all
1730
+ ds = @ds.with_extend(Module.new do
1731
+ def check_return
1732
+ use_cursor.each{|r| return}
1733
+ end
1734
+ end)
1735
+ ds.check_return
1736
+ ds.all.must_equal ds.use_cursor.all
1738
1737
  end
1739
1738
  end
1740
1739
 
@@ -1,5 +1,6 @@
1
1
  require 'rubygems'
2
2
  require 'logger'
3
+ require "#{File.dirname(File.dirname(__FILE__))}/sequel_warning.rb"
3
4
 
4
5
  if ENV['COVERAGE']
5
6
  require File.join(File.dirname(File.expand_path(__FILE__)), "../sequel_coverage")
@@ -457,9 +457,7 @@ describe "SQLite dataset" do
457
457
  end
458
458
 
459
459
  it "should have #explain work when identifier_output_method is modified" do
460
- ds = DB[:test]
461
- ds.identifier_output_method = :upcase
462
- ds.explain.must_be_kind_of(String)
460
+ DB[:test].with_identifier_output_method(:upcase).explain.must_be_kind_of(String)
463
461
  end
464
462
  end
465
463
 
@@ -1899,8 +1899,9 @@ describe "Database#raise_error" do
1899
1899
  def @db.database_error_regexps
1900
1900
  {/foo/ => Sequel::DatabaseDisconnectError, /bar/ => Sequel::ConstraintViolation}
1901
1901
  end
1902
- proc{@db.send(:raise_error, Interrupt.new('foo'))}.must_raise(Sequel::DatabaseDisconnectError)
1903
- proc{@db.send(:raise_error, Interrupt.new('bar'))}.must_raise(Sequel::ConstraintViolation)
1902
+ e = Class.new(StandardError)
1903
+ proc{@db.send(:raise_error, e.new('foo'))}.must_raise(Sequel::DatabaseDisconnectError)
1904
+ proc{@db.send(:raise_error, e.new('bar'))}.must_raise(Sequel::ConstraintViolation)
1904
1905
  end
1905
1906
  end
1906
1907
 
@@ -89,6 +89,33 @@ describe "Dataset" do
89
89
  @dataset.send(:output_identifier, "at_b_C").must_equal :C_b_ta
90
90
  end
91
91
 
92
+ it "should have with_quote_identifiers method which returns cloned dataset with changed literalization of identifiers" do
93
+ @dataset.with_quote_identifiers(true).literal(:a).must_equal '"a"'
94
+ @dataset.with_quote_identifiers(false).literal(:a).must_equal 'a'
95
+ ds = @dataset.freeze.with_quote_identifiers(false)
96
+ ds.literal(:a).must_equal 'a'
97
+ ds.frozen?.must_equal true
98
+ end
99
+
100
+ it "should have with_identifier_input_method method which returns cloned dataset with changed literalization of identifiers" do
101
+ @dataset.with_identifier_input_method(:upcase).literal(:a).must_equal 'A'
102
+ @dataset.with_identifier_input_method(:downcase).literal(:A).must_equal 'a'
103
+ @dataset.with_identifier_input_method(:reverse).literal(:at_b).must_equal 'b_ta'
104
+ ds = @dataset.freeze.with_identifier_input_method(:reverse)
105
+ ds.frozen?.must_equal true
106
+ ds.literal(:at_b).must_equal 'b_ta'
107
+ end
108
+
109
+ it "should have with_identifier_output_method method which returns cloned dataset with changed identifiers returned from the database" do
110
+ @dataset.send(:output_identifier, "at_b_C").must_equal :at_b_C
111
+ @dataset.with_identifier_output_method(:upcase).send(:output_identifier, "at_b_C").must_equal :AT_B_C
112
+ @dataset.with_identifier_output_method(:downcase).send(:output_identifier, "at_b_C").must_equal :at_b_c
113
+ @dataset.with_identifier_output_method(:reverse).send(:output_identifier, "at_b_C").must_equal :C_b_ta
114
+ ds = @dataset.freeze.with_identifier_output_method(:reverse)
115
+ ds.send(:output_identifier, "at_b_C").must_equal :C_b_ta
116
+ ds.frozen?.must_equal true
117
+ end
118
+
92
119
  it "should have output_identifier handle empty identifiers" do
93
120
  @dataset.send(:output_identifier, "").must_equal :untitled
94
121
  @dataset.identifier_output_method = :upcase
@@ -167,8 +194,7 @@ describe "Dataset#==" do
167
194
 
168
195
  it "should be different for datasets with different SQL" do
169
196
  ds = @db[:t]
170
- ds.quote_identifiers = true
171
- ds.wont_equal @db[:t]
197
+ ds.with_quote_identifiers(true).wont_equal ds
172
198
  end
173
199
  end
174
200
 
@@ -194,8 +220,7 @@ describe "Dataset#hash" do
194
220
 
195
221
  it "should be different for datasets with different SQL" do
196
222
  ds = @db[:t]
197
- ds.quote_identifiers = true
198
- ds.hash.wont_equal @db[:t].hash
223
+ ds.with_quote_identifiers(true).hash.wont_equal ds.hash
199
224
  end
200
225
  end
201
226
 
@@ -937,7 +962,7 @@ describe "Dataset#literal" do
937
962
  end
938
963
 
939
964
  it "should support spaces inside column names" do
940
- @ds.quote_identifiers = true
965
+ @ds = @ds.with_quote_identifiers(true)
941
966
  @ds.literal(:"AB C").must_equal '"AB C"'
942
967
  @ds.literal(:"Zvas htoy__aB cD").must_equal '"Zvas htoy"."aB cD"'
943
968
  @ds.literal(:"aB cD___XX XX").must_equal '"aB cD" AS "XX XX"'
@@ -1061,7 +1086,7 @@ describe "Dataset#literal" do
1061
1086
  end
1062
1087
 
1063
1088
  it "should not modify literal strings" do
1064
- @dataset.quote_identifiers = true
1089
+ @dataset = @dataset.with_quote_identifiers(true)
1065
1090
  @dataset.literal(Sequel.lit('col1 + 2')).must_equal 'col1 + 2'
1066
1091
  @dataset.update_sql(Sequel::SQL::Identifier.new(Sequel.lit('a')) => Sequel.lit('a + 2')).must_equal 'UPDATE "test" SET a = a + 2'
1067
1092
  end
@@ -1115,12 +1140,11 @@ describe "Dataset#from" do
1115
1140
  end
1116
1141
 
1117
1142
  it "should treat string arguments as identifiers" do
1118
- @dataset.quote_identifiers = true
1119
- @dataset.from('a').select_sql.must_equal "SELECT * FROM \"a\""
1143
+ @dataset.with_quote_identifiers(true).from('a').select_sql.must_equal "SELECT * FROM \"a\""
1120
1144
  end
1121
1145
 
1122
1146
  it "should not treat literal strings or blobs as identifiers" do
1123
- @dataset.quote_identifiers = true
1147
+ @dataset = @dataset.with_quote_identifiers(true)
1124
1148
  @dataset.from(Sequel.lit('a')).select_sql.must_equal "SELECT * FROM a"
1125
1149
  @dataset.from(Sequel.blob('a')).select_sql.must_equal "SELECT * FROM 'a'"
1126
1150
  end
@@ -1671,6 +1695,31 @@ describe "Dataset#offset" do
1671
1695
  end
1672
1696
  end
1673
1697
 
1698
+ describe "Dataset#with_extend" do
1699
+ it "should returned clone dataset extended with given modules" do
1700
+ d = Sequel.mock.dataset
1701
+ m1 = Module.new{def a; 1; end}
1702
+ m2 = Module.new{def b; a+2; end}
1703
+ d.with_extend(m1, m2).b.must_equal 3
1704
+ d.respond_to?(:b).must_equal false
1705
+ ds = d.freeze.with_extend(m1, m2)
1706
+ ds.b.must_equal 3
1707
+ ds.frozen?.must_equal true
1708
+ end
1709
+ end
1710
+
1711
+ describe "Dataset#with_row_proc" do
1712
+ it "should returned clone dataset with the given row_proc" do
1713
+ d = Sequel.mock.dataset
1714
+ l = lambda{|r| r}
1715
+ d.with_row_proc(l).row_proc.must_equal l
1716
+ assert_equal nil, d.row_proc
1717
+ ds = d.freeze.with_row_proc(l)
1718
+ ds.frozen?.must_equal true
1719
+ ds.row_proc.must_equal l
1720
+ end
1721
+ end
1722
+
1674
1723
  describe "Dataset#naked" do
1675
1724
  it "should returned clone dataset without row_proc" do
1676
1725
  d = Sequel.mock.dataset
@@ -2126,8 +2175,7 @@ end
2126
2175
 
2127
2176
  describe "Dataset#join_table" do
2128
2177
  before do
2129
- @d = Sequel.mock.dataset.from(:items)
2130
- @d.quote_identifiers = true
2178
+ @d = Sequel.mock.dataset.from(:items).with_quote_identifiers(true)
2131
2179
  end
2132
2180
 
2133
2181
  it "should format the JOIN clause properly" do
@@ -2791,7 +2839,7 @@ describe "Dataset#single_value!" do
2791
2839
 
2792
2840
  it "should call each and return the first value of the first record" do
2793
2841
  @db.fetch = [{:a=>1, :b=>2}, {:a=>3, :b=>4}]
2794
- @db[:test].single_value!.to_s.must_match /\A(1|2)\z/
2842
+ @db[:test].single_value!.to_s.must_match(/\A(1|2)\z/)
2795
2843
  @db.sqls.must_equal ['SELECT * FROM test']
2796
2844
  end
2797
2845
 
@@ -3302,8 +3350,7 @@ describe "Dataset#insert_sql" do
3302
3350
  end
3303
3351
 
3304
3352
  it "should quote string keys" do
3305
- @ds.quote_identifiers = true
3306
- @ds.insert_sql('c' => 'd').must_equal "INSERT INTO \"items\" (\"c\") VALUES ('d')"
3353
+ @ds.with_quote_identifiers(true).insert_sql('c' => 'd').must_equal "INSERT INTO \"items\" (\"c\") VALUES ('d')"
3307
3354
  end
3308
3355
 
3309
3356
  it "should accept array subscript references" do
@@ -3712,7 +3759,6 @@ describe "Dataset prepared statements and bound variables " do
3712
3759
  end
3713
3760
 
3714
3761
  it "should handle usage with Dataset.prepared_statements_module" do
3715
- m = Module.new
3716
3762
  @ds.extend(Sequel::Dataset.send(:prepared_statements_module, :prepare_bind, [Sequel::Dataset::ArgumentMapper, Sequel::Dataset::PreparedStatementMethods]){def foo; :bar; end})
3717
3763
  @ds.foo.must_equal :bar
3718
3764
  @ds.prepared_statement_name = 'foo'
@@ -4016,7 +4062,7 @@ describe "Sequel::Dataset #with and #with_recursive" do
4016
4062
  end
4017
4063
 
4018
4064
  it "#with and #with_recursive should quote the columns in the :args option" do
4019
- @ds.quote_identifiers = true
4065
+ @ds = @ds.with_quote_identifiers(true)
4020
4066
  @ds.with(:t, @db[:x], :args=>[:b]).sql.must_equal 'WITH "t"("b") AS (SELECT * FROM x) SELECT * FROM "t"'
4021
4067
  @ds.with_recursive(:t, @db[:x], @db[:t], :args=>[:b, :c]).sql.must_equal 'WITH "t"("b", "c") AS (SELECT * FROM x UNION ALL SELECT * FROM t) SELECT * FROM "t"'
4022
4068
  end
@@ -4631,8 +4677,7 @@ end
4631
4677
 
4632
4678
  describe "Dataset emulating bitwise operator support" do
4633
4679
  before do
4634
- @ds = Sequel::Database.new.dataset
4635
- @ds.quote_identifiers = true
4680
+ @ds = Sequel::Database.new.dataset.with_quote_identifiers(true)
4636
4681
  def @ds.complex_expression_sql_append(sql, op, args)
4637
4682
  complex_expression_arg_pairs_append(sql, args){|a, b| Sequel.function(:bitand, a, b)}
4638
4683
  end
@@ -4681,20 +4726,19 @@ describe "Dataset extensions" do
4681
4726
  end
4682
4727
 
4683
4728
  it "should be able to register an extension with a block and Database#extension call the block" do
4684
- @ds.quote_identifiers = false
4729
+ @ds = @ds.with_quote_identifiers(false)
4685
4730
  Sequel::Dataset.register_extension(:foo){|db| db.quote_identifiers = true}
4686
4731
  @ds.extension(:foo).quote_identifiers?.must_equal true
4687
4732
  end
4688
4733
 
4689
4734
  it "should be able to register an extension with a callable and Database#extension call the callable" do
4690
- @ds.quote_identifiers = false
4735
+ @ds = @ds.with_quote_identifiers(false)
4691
4736
  Sequel::Dataset.register_extension(:foo, proc{|db| db.quote_identifiers = true})
4692
4737
  @ds.extension(:foo).quote_identifiers?.must_equal true
4693
4738
  end
4694
4739
 
4695
4740
  it "should be able to load multiple extensions in the same call" do
4696
- @ds.quote_identifiers = false
4697
- @ds.identifier_input_method = :downcase
4741
+ @ds = @ds.with_quote_identifiers(false).with_identifier_input_method(:downcase)
4698
4742
  Sequel::Dataset.register_extension(:foo, proc{|ds| ds.quote_identifiers = true})
4699
4743
  Sequel::Dataset.register_extension(:bar, proc{|ds| ds.identifier_input_method = nil})
4700
4744
  ds = @ds.extension(:foo, :bar)