sequel 3.20.0 → 3.21.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 (65) hide show
  1. data/CHANGELOG +32 -0
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +1 -1
  4. data/Rakefile +13 -3
  5. data/bin/sequel +18 -5
  6. data/doc/active_record.rdoc +4 -4
  7. data/doc/opening_databases.rdoc +38 -1
  8. data/doc/release_notes/3.21.0.txt +87 -0
  9. data/doc/validations.rdoc +2 -2
  10. data/lib/sequel/adapters/informix.rb +1 -1
  11. data/lib/sequel/adapters/jdbc/h2.rb +2 -5
  12. data/lib/sequel/adapters/jdbc/mssql.rb +1 -4
  13. data/lib/sequel/adapters/jdbc/mysql.rb +1 -4
  14. data/lib/sequel/adapters/jdbc/postgresql.rb +1 -6
  15. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -8
  16. data/lib/sequel/adapters/shared/mssql.rb +8 -0
  17. data/lib/sequel/adapters/shared/mysql.rb +23 -3
  18. data/lib/sequel/adapters/shared/oracle.rb +2 -2
  19. data/lib/sequel/adapters/tinytds.rb +125 -0
  20. data/lib/sequel/database/connecting.rb +1 -1
  21. data/lib/sequel/database/schema_methods.rb +37 -5
  22. data/lib/sequel/dataset/sql.rb +6 -6
  23. data/lib/sequel/extensions/schema_dumper.rb +1 -1
  24. data/lib/sequel/model/base.rb +50 -0
  25. data/lib/sequel/model/plugins.rb +0 -55
  26. data/lib/sequel/plugins/association_autoreloading.rb +48 -0
  27. data/lib/sequel/plugins/validation_class_methods.rb +6 -5
  28. data/lib/sequel/plugins/validation_helpers.rb +2 -2
  29. data/lib/sequel/version.rb +1 -1
  30. data/spec/adapters/firebird_spec.rb +6 -6
  31. data/spec/adapters/informix_spec.rb +2 -2
  32. data/spec/adapters/mssql_spec.rb +18 -13
  33. data/spec/adapters/mysql_spec.rb +47 -20
  34. data/spec/adapters/oracle_spec.rb +40 -4
  35. data/spec/adapters/postgres_spec.rb +14 -14
  36. data/spec/adapters/spec_helper.rb +1 -1
  37. data/spec/adapters/sqlite_spec.rb +8 -8
  38. data/spec/core/connection_pool_spec.rb +18 -17
  39. data/spec/core/core_sql_spec.rb +18 -18
  40. data/spec/core/database_spec.rb +62 -62
  41. data/spec/core/dataset_spec.rb +105 -92
  42. data/spec/core/expression_filters_spec.rb +2 -2
  43. data/spec/core/schema_spec.rb +6 -6
  44. data/spec/core/version_spec.rb +1 -1
  45. data/spec/extensions/association_autoreloading_spec.rb +94 -0
  46. data/spec/extensions/blank_spec.rb +6 -6
  47. data/spec/extensions/looser_typecasting_spec.rb +1 -1
  48. data/spec/extensions/migration_spec.rb +6 -6
  49. data/spec/extensions/pagination_spec.rb +2 -2
  50. data/spec/extensions/pretty_table_spec.rb +2 -2
  51. data/spec/extensions/query_spec.rb +2 -2
  52. data/spec/extensions/schema_dumper_spec.rb +2 -1
  53. data/spec/extensions/single_table_inheritance_spec.rb +1 -1
  54. data/spec/extensions/sql_expr_spec.rb +1 -1
  55. data/spec/extensions/string_date_time_spec.rb +4 -4
  56. data/spec/extensions/validation_class_methods_spec.rb +2 -2
  57. data/spec/integration/dataset_test.rb +8 -3
  58. data/spec/integration/plugin_test.rb +5 -5
  59. data/spec/integration/prepared_statement_test.rb +1 -1
  60. data/spec/integration/schema_test.rb +7 -0
  61. data/spec/integration/spec_helper.rb +14 -1
  62. data/spec/integration/timezone_test.rb +4 -4
  63. data/spec/integration/type_test.rb +1 -1
  64. data/spec/model/model_spec.rb +3 -3
  65. metadata +9 -4
@@ -3,7 +3,7 @@ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
3
3
  Regexp.send(:include, Sequel::SQL::StringMethods)
4
4
  String.send(:include, Sequel::SQL::StringMethods)
5
5
 
6
- context "Blockless Ruby Filters" do
6
+ describe "Blockless Ruby Filters" do
7
7
  before do
8
8
  db = Sequel::Database.new
9
9
  db.quote_identifiers = false
@@ -481,7 +481,7 @@ context "Blockless Ruby Filters" do
481
481
  end
482
482
  end
483
483
 
484
- context Sequel::SQL::VirtualRow do
484
+ describe Sequel::SQL::VirtualRow do
485
485
  before do
486
486
  db = Sequel::Database.new
487
487
  db.quote_identifiers = true
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
- context "DB#create_table" do
3
+ describe "DB#create_table" do
4
4
  before do
5
5
  @db = SchemaDummyDatabase.new
6
6
  end
@@ -543,7 +543,7 @@ context "DB#create_table" do
543
543
  end
544
544
  end
545
545
 
546
- context "DB#create_table!" do
546
+ describe "DB#create_table!" do
547
547
  before do
548
548
  @db = SchemaDummyDatabase.new
549
549
  end
@@ -554,7 +554,7 @@ context "DB#create_table!" do
554
554
  end
555
555
  end
556
556
 
557
- context "DB#create_table?" do
557
+ describe "DB#create_table?" do
558
558
  before do
559
559
  @db = SchemaDummyDatabase.new
560
560
  end
@@ -572,7 +572,7 @@ context "DB#create_table?" do
572
572
  end
573
573
  end
574
574
 
575
- context "DB#drop_table" do
575
+ describe "DB#drop_table" do
576
576
  before do
577
577
  @db = SchemaDummyDatabase.new
578
578
  end
@@ -583,7 +583,7 @@ context "DB#drop_table" do
583
583
  end
584
584
  end
585
585
 
586
- context "DB#alter_table" do
586
+ describe "DB#alter_table" do
587
587
  before do
588
588
  @db = SchemaDummyDatabase.new
589
589
  end
@@ -763,7 +763,7 @@ context "DB#alter_table" do
763
763
  end
764
764
  end
765
765
 
766
- context "Schema Parser" do
766
+ describe "Schema Parser" do
767
767
  before do
768
768
  @sqls = []
769
769
  @db = Sequel::Database.new
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
- context "Sequel.version" do
3
+ describe "Sequel.version" do
4
4
  specify "should be in the form X.Y.Z with all being numbers" do
5
5
  Sequel.version.should =~ /\A\d+\.\d+\.\d+\z/
6
6
  end
@@ -0,0 +1,94 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "AssociationAutoreloading plugin" do
4
+ before do
5
+ @c = Class.new(Sequel::Model)
6
+ @c.plugin :association_autoreloading
7
+ @Artist = Class.new(@c).set_dataset(:artists)
8
+ ds1 = @Artist.dataset
9
+ def ds1.fetch_rows(s)
10
+ (MODEL_DB.sqls ||= []) << s
11
+ yield({:id=>2, :name=>'Ar'})
12
+ end
13
+ @Album = Class.new(@c).set_dataset(:albums)
14
+ @Artist.columns :id, :name
15
+ @Album.columns :id, :name, :artist_id
16
+ @Album.db_schema[:artist_id][:type] = :integer
17
+ @Album.many_to_one :artist, :class=>@Artist
18
+ MODEL_DB.reset
19
+ end
20
+
21
+ specify "should reload many_to_one association when foreign key is modified" do
22
+ album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
23
+ album.artist
24
+ MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1']
25
+ MODEL_DB.reset
26
+
27
+ album.artist_id = 1
28
+ album.artist
29
+ MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 1) LIMIT 1']
30
+ end
31
+
32
+ specify "should not reload when value has not changed" do
33
+ album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
34
+ album.artist
35
+ MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1']
36
+ MODEL_DB.reset
37
+
38
+ album.artist_id = 2
39
+ album.artist
40
+ MODEL_DB.sqls.should == []
41
+
42
+ album.artist_id = "2"
43
+ album.artist
44
+ MODEL_DB.sqls.should == []
45
+ end
46
+
47
+ specify "should reload all associations which use the foreign key" do
48
+ @Album.many_to_one :other_artist, :key => :artist_id, :foreign_key => :id, :class => @Artist
49
+ album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
50
+ album.artist
51
+ album.other_artist
52
+ MODEL_DB.reset
53
+
54
+ album.artist_id = 1
55
+ album.artist
56
+ MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 1) LIMIT 1']
57
+ MODEL_DB.reset
58
+
59
+ album.other_artist
60
+ MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 1) LIMIT 1']
61
+ end
62
+
63
+ specify "should work with composite keys" do
64
+ @Album.many_to_one :composite_artist, :key => [:artist_id, :name], :primary_key => [:id, :name], :class => @Artist
65
+ album = @Album.load(:id => 1, :name=>'Al', :artist_id=>2)
66
+ album.composite_artist
67
+ MODEL_DB.reset
68
+
69
+ album.artist_id = 1
70
+ album.composite_artist
71
+ MODEL_DB.sqls.should == ["SELECT * FROM artists WHERE ((artists.id = 1) AND (artists.name = 'Al')) LIMIT 1"]
72
+ MODEL_DB.reset
73
+
74
+ album.name = 'Al2'
75
+ album.composite_artist
76
+ MODEL_DB.sqls.should == ["SELECT * FROM artists WHERE ((artists.id = 1) AND (artists.name = 'Al2')) LIMIT 1"]
77
+ end
78
+
79
+ specify "should work with subclasses" do
80
+ salbum = Class.new(@Album)
81
+ oartist = Class.new(@c).set_dataset(:oartist)
82
+ oartist.columns :id, :name
83
+ salbum.many_to_one :artist2, :class=>oartist, :key=>:artist_id
84
+ album = salbum.load(:id => 1, :name=>'Al', :artist_id=>2)
85
+ album.artist
86
+ MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 2) LIMIT 1']
87
+ MODEL_DB.reset
88
+
89
+ album.artist_id = 1
90
+ album.artist
91
+ MODEL_DB.sqls.should == ['SELECT * FROM artists WHERE (artists.id = 1) LIMIT 1']
92
+ end
93
+
94
+ end
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
- context "Object#blank?" do
3
+ describe "Object#blank?" do
4
4
  specify "it should be true if the object responds true to empty?" do
5
5
  [].blank?.should == true
6
6
  {}.blank?.should == true
@@ -16,7 +16,7 @@ context "Object#blank?" do
16
16
  end
17
17
  end
18
18
 
19
- context "Numeric#blank?" do
19
+ describe "Numeric#blank?" do
20
20
  specify "it should always be false" do
21
21
  1.blank?.should == false
22
22
  0.blank?.should == false
@@ -31,25 +31,25 @@ context "Numeric#blank?" do
31
31
  end
32
32
  end
33
33
 
34
- context "NilClass#blank?" do
34
+ describe "NilClass#blank?" do
35
35
  specify "it should always be true" do
36
36
  nil.blank?.should == true
37
37
  end
38
38
  end
39
39
 
40
- context "TrueClass#blank?" do
40
+ describe "TrueClass#blank?" do
41
41
  specify "it should always be false" do
42
42
  true.blank?.should == false
43
43
  end
44
44
  end
45
45
 
46
- context "FalseClass#blank?" do
46
+ describe "FalseClass#blank?" do
47
47
  specify "it should always be true" do
48
48
  false.blank?.should == true
49
49
  end
50
50
  end
51
51
 
52
- context "String#blank?" do
52
+ describe "String#blank?" do
53
53
  specify "it should be true if the string is empty" do
54
54
  ''.blank?.should == true
55
55
  end
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
- context "LooserTypecasting Extension" do
3
+ describe "LooserTypecasting Extension" do
4
4
  before do
5
5
  @db = Sequel::Database.new({})
6
6
  def @db.schema(*args)
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
- context "Migration.descendants" do
3
+ describe "Migration.descendants" do
4
4
  before do
5
5
  Sequel::Migration.descendants.clear
6
6
  end
@@ -28,7 +28,7 @@ context "Migration.descendants" do
28
28
  end
29
29
  end
30
30
 
31
- context "Migration.apply" do
31
+ describe "Migration.apply" do
32
32
  before do
33
33
  @c = Class.new do
34
34
  define_method(:one) {|x| [1111, x]}
@@ -57,7 +57,7 @@ context "Migration.apply" do
57
57
  end
58
58
  end
59
59
 
60
- context "SimpleMigration#apply" do
60
+ describe "SimpleMigration#apply" do
61
61
  before do
62
62
  @c = Class.new do
63
63
  define_method(:one) {|x| [1111, x]}
@@ -86,7 +86,7 @@ context "SimpleMigration#apply" do
86
86
  end
87
87
  end
88
88
 
89
- context "Reversible Migrations with Sequel.migration{change{}}" do
89
+ describe "Reversible Migrations with Sequel.migration{change{}}" do
90
90
  before do
91
91
  @c = Class.new do
92
92
  self::AT = Class.new do
@@ -193,7 +193,7 @@ context "Reversible Migrations with Sequel.migration{change{}}" do
193
193
  end
194
194
  end
195
195
 
196
- context "Sequel::IntegerMigrator" do
196
+ describe "Sequel::IntegerMigrator" do
197
197
  before do
198
198
  dbc = Class.new(MockDatabase) do
199
199
  attr_reader :drops, :tables_created, :columns_created, :versions
@@ -313,7 +313,7 @@ context "Sequel::IntegerMigrator" do
313
313
  end
314
314
  end
315
315
 
316
- context "Sequel::TimestampMigrator" do
316
+ describe "Sequel::TimestampMigrator" do
317
317
  before do
318
318
  $sequel_migration_version = 0
319
319
  $sequel_migration_files = []
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
- context "A paginated dataset" do
3
+ describe "A paginated dataset" do
4
4
  before do
5
5
  @d = Sequel::Dataset.new(nil)
6
6
  @d.meta_def(:count) {153}
@@ -76,7 +76,7 @@ context "A paginated dataset" do
76
76
  end
77
77
  end
78
78
 
79
- context "Dataset#each_page" do
79
+ describe "Dataset#each_page" do
80
80
  before do
81
81
  @d = Sequel::Dataset.new(nil).from(:items)
82
82
  @d.meta_def(:count) {153}
@@ -2,7 +2,7 @@ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
3
  require 'stringio'
4
4
 
5
- context "Dataset#print" do
5
+ describe "Dataset#print" do
6
6
  before do
7
7
  @output = StringIO.new
8
8
  @orig_stdout = $stdout
@@ -35,7 +35,7 @@ context "Dataset#print" do
35
35
  end
36
36
  end
37
37
 
38
- context "PrettyTable" do
38
+ describe "PrettyTable" do
39
39
  before do
40
40
  @data1 = [
41
41
  {:x => 3, :y => 4}
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
- context "Database#dataset" do
3
+ describe "Database#dataset" do
4
4
  before do
5
5
  @db = Sequel::Database.new
6
6
  end
@@ -12,7 +12,7 @@ context "Database#dataset" do
12
12
  end
13
13
  end
14
14
 
15
- context "Dataset#query" do
15
+ describe "Dataset#query" do
16
16
  before do
17
17
  @d = Sequel::Dataset.new(nil)
18
18
  end
@@ -291,7 +291,7 @@ END_MIG
291
291
  ["double precision", "timestamp with time zone", "timestamp without time zone",
292
292
  "time with time zone", "time without time zone", "character varying(20)"] +
293
293
  %w"nvarchar ntext smalldatetime smallmoney binary varbinary nchar" +
294
- ["timestamp(6) without time zone", "timestamp(6) with time zone", "int(12) unsigned"]
294
+ ["timestamp(6) without time zone", "timestamp(6) with time zone", "int(12) unsigned", 'bigint unsigned']
295
295
  @d.meta_def(:schema) do |t, *o|
296
296
  i = 0
297
297
  types.map{|x| [:"c#{i+=1}", {:db_type=>x, :allow_null=>true}]}
@@ -362,6 +362,7 @@ create_table(:x) do
362
362
  DateTime :c62, :size=>6
363
363
  DateTime :c63, :size=>6
364
364
  Integer :c64
365
+ Bignum :c65
365
366
  end
366
367
  END_MIG
367
368
  @d.dump_table_schema(:x).should == table.chomp
@@ -114,7 +114,7 @@ describe Sequel::Model, "#sti_key" do
114
114
  StiTestSub1B.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.kind IN ('StiTestSub1B'))"
115
115
  end
116
116
 
117
- context "with custom options" do
117
+ describe "with custom options" do
118
118
  before do
119
119
  class ::StiTest2 < Sequel::Model
120
120
  columns :id, :kind
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
- context "Sequel sql_expr extension" do
3
+ describe "Sequel sql_expr extension" do
4
4
  specify "Object#sql_expr should wrap the object in a GenericComplexExpression" do
5
5
  o = Object.new
6
6
  s = o.sql_expr
@@ -1,6 +1,6 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
- context "String#to_time" do
3
+ describe "String#to_time" do
4
4
  specify "should convert the string into a Time object" do
5
5
  "2007-07-11".to_time.should == Time.parse("2007-07-11")
6
6
  "06:30".to_time.should == Time.parse("06:30")
@@ -11,7 +11,7 @@ context "String#to_time" do
11
11
  end
12
12
  end
13
13
 
14
- context "String#to_date" do
14
+ describe "String#to_date" do
15
15
  after do
16
16
  Sequel.convert_two_digit_years = true
17
17
  end
@@ -34,7 +34,7 @@ context "String#to_date" do
34
34
  end
35
35
  end
36
36
 
37
- context "String#to_datetime" do
37
+ describe "String#to_datetime" do
38
38
  after do
39
39
  Sequel.convert_two_digit_years = true
40
40
  end
@@ -57,7 +57,7 @@ context "String#to_datetime" do
57
57
  end
58
58
  end
59
59
 
60
- context "String#to_sequel_time" do
60
+ describe "String#to_sequel_time" do
61
61
  after do
62
62
  Sequel.datetime_class = Time
63
63
  Sequel.convert_two_digit_years = true
@@ -583,7 +583,7 @@ describe Sequel::Model do
583
583
  end
584
584
  end
585
585
 
586
- context "Superclass validations" do
586
+ describe "Superclass validations" do
587
587
  before do
588
588
  @c1 = Class.new(Sequel::Model)
589
589
  @c1.class_eval do
@@ -635,7 +635,7 @@ context "Superclass validations" do
635
635
  end
636
636
  end
637
637
 
638
- context ".validates with block" do
638
+ describe ".validates with block" do
639
639
  specify "should support calling .each" do
640
640
  @c = Class.new(Sequel::Model)
641
641
  @c.class_eval do
@@ -191,7 +191,7 @@ describe Sequel::Database do
191
191
  end
192
192
  end
193
193
 
194
- context Sequel::Dataset do
194
+ describe Sequel::Dataset do
195
195
  before do
196
196
  INTEGRATION_DB.create_table! :items do
197
197
  primary_key :id
@@ -386,6 +386,11 @@ if INTEGRATION_DB.dataset.supports_cte?
386
386
  ps.call(:n=>3).should == [{:id=>5, :parent_id=>3}, {:id=>6, :parent_id=>5}]
387
387
  ps.call(:n=>5).should == [{:id=>6, :parent_id=>5}]
388
388
  end
389
+
390
+ specify "should support joining a dataset with a CTE" do
391
+ @ds.inner_join(@db[:t].with(:t, @ds.filter(:parent_id=>nil)), :id => :id).select(:i1__id).order(:i1__id).map(:id).should == [1,2]
392
+ @db[:t].with(:t, @ds).inner_join(@db[:s].with(:s, @ds.filter(:parent_id=>nil)), :id => :id).select(:t__id).order(:t__id).map(:id).should == [1,2]
393
+ end
389
394
  end
390
395
  end
391
396
 
@@ -480,13 +485,13 @@ describe Sequel::SQL::Constants do
480
485
  cspecify "should have working CURRENT_TIME", [:do, :mysql], [:jdbc, :sqlite], [:mysql2] do
481
486
  @db.create_table!(:constants){Time :t, :only_time=>true}
482
487
  @ds.insert(:t=>Sequel::CURRENT_TIME)
483
- (Time.now - @c[@ds.get(:t)]).should be_close(0, 1)
488
+ (Time.now - @c[@ds.get(:t)]).should be_within(1).of(0)
484
489
  end
485
490
 
486
491
  cspecify "should have working CURRENT_TIMESTAMP", [:jdbc, :sqlite] do
487
492
  @db.create_table!(:constants){DateTime :ts}
488
493
  @ds.insert(:ts=>Sequel::CURRENT_TIMESTAMP)
489
- (Time.now - @c[@ds.get(:ts)]).should be_close(0, 1)
494
+ (Time.now - @c[@ds.get(:ts)]).should be_within(1).of(0)
490
495
  end
491
496
  end
492
497