sequel 3.28.0 → 3.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. data/CHANGELOG +119 -3
  2. data/Rakefile +5 -3
  3. data/bin/sequel +1 -5
  4. data/doc/model_hooks.rdoc +9 -1
  5. data/doc/opening_databases.rdoc +49 -40
  6. data/doc/prepared_statements.rdoc +27 -6
  7. data/doc/release_notes/3.28.0.txt +2 -2
  8. data/doc/release_notes/3.29.0.txt +459 -0
  9. data/doc/sharding.rdoc +7 -1
  10. data/doc/testing.rdoc +18 -9
  11. data/doc/transactions.rdoc +41 -1
  12. data/lib/sequel/adapters/ado.rb +28 -17
  13. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  14. data/lib/sequel/adapters/amalgalite.rb +11 -7
  15. data/lib/sequel/adapters/db2.rb +122 -70
  16. data/lib/sequel/adapters/dbi.rb +15 -15
  17. data/lib/sequel/adapters/do.rb +5 -36
  18. data/lib/sequel/adapters/do/mysql.rb +0 -5
  19. data/lib/sequel/adapters/do/postgres.rb +0 -5
  20. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  21. data/lib/sequel/adapters/firebird.rb +3 -6
  22. data/lib/sequel/adapters/ibmdb.rb +24 -16
  23. data/lib/sequel/adapters/informix.rb +2 -4
  24. data/lib/sequel/adapters/jdbc.rb +47 -11
  25. data/lib/sequel/adapters/jdbc/as400.rb +5 -24
  26. data/lib/sequel/adapters/jdbc/db2.rb +0 -5
  27. data/lib/sequel/adapters/jdbc/derby.rb +217 -0
  28. data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
  29. data/lib/sequel/adapters/jdbc/h2.rb +10 -12
  30. data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
  31. data/lib/sequel/adapters/jdbc/informix.rb +0 -5
  32. data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
  33. data/lib/sequel/adapters/jdbc/mysql.rb +0 -10
  34. data/lib/sequel/adapters/jdbc/oracle.rb +70 -3
  35. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -11
  36. data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
  38. data/lib/sequel/adapters/jdbc/transactions.rb +56 -7
  39. data/lib/sequel/adapters/mock.rb +315 -0
  40. data/lib/sequel/adapters/mysql.rb +64 -51
  41. data/lib/sequel/adapters/mysql2.rb +15 -9
  42. data/lib/sequel/adapters/odbc.rb +13 -6
  43. data/lib/sequel/adapters/odbc/db2.rb +0 -4
  44. data/lib/sequel/adapters/odbc/mssql.rb +0 -5
  45. data/lib/sequel/adapters/openbase.rb +2 -4
  46. data/lib/sequel/adapters/oracle.rb +333 -51
  47. data/lib/sequel/adapters/postgres.rb +80 -27
  48. data/lib/sequel/adapters/shared/access.rb +0 -6
  49. data/lib/sequel/adapters/shared/db2.rb +13 -15
  50. data/lib/sequel/adapters/shared/firebird.rb +6 -6
  51. data/lib/sequel/adapters/shared/mssql.rb +23 -18
  52. data/lib/sequel/adapters/shared/mysql.rb +6 -6
  53. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
  54. data/lib/sequel/adapters/shared/oracle.rb +185 -30
  55. data/lib/sequel/adapters/shared/postgres.rb +35 -18
  56. data/lib/sequel/adapters/shared/progress.rb +0 -6
  57. data/lib/sequel/adapters/shared/sqlite.rb +116 -37
  58. data/lib/sequel/adapters/sqlite.rb +16 -8
  59. data/lib/sequel/adapters/swift.rb +5 -5
  60. data/lib/sequel/adapters/swift/mysql.rb +0 -5
  61. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  62. data/lib/sequel/adapters/swift/sqlite.rb +6 -4
  63. data/lib/sequel/adapters/tinytds.rb +13 -10
  64. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -0
  65. data/lib/sequel/core.rb +40 -0
  66. data/lib/sequel/database/connecting.rb +1 -2
  67. data/lib/sequel/database/dataset.rb +3 -3
  68. data/lib/sequel/database/dataset_defaults.rb +58 -0
  69. data/lib/sequel/database/misc.rb +62 -2
  70. data/lib/sequel/database/query.rb +113 -49
  71. data/lib/sequel/database/schema_methods.rb +7 -2
  72. data/lib/sequel/dataset/actions.rb +37 -19
  73. data/lib/sequel/dataset/features.rb +24 -0
  74. data/lib/sequel/dataset/graph.rb +7 -6
  75. data/lib/sequel/dataset/misc.rb +11 -3
  76. data/lib/sequel/dataset/mutation.rb +2 -3
  77. data/lib/sequel/dataset/prepared_statements.rb +6 -4
  78. data/lib/sequel/dataset/query.rb +46 -15
  79. data/lib/sequel/dataset/sql.rb +28 -4
  80. data/lib/sequel/extensions/named_timezones.rb +5 -0
  81. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  82. data/lib/sequel/model.rb +2 -1
  83. data/lib/sequel/model/associations.rb +115 -33
  84. data/lib/sequel/model/base.rb +91 -31
  85. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  86. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  87. data/lib/sequel/plugins/force_encoding.rb +6 -6
  88. data/lib/sequel/plugins/identity_map.rb +1 -1
  89. data/lib/sequel/plugins/many_through_many.rb +6 -10
  90. data/lib/sequel/plugins/prepared_statements.rb +12 -1
  91. data/lib/sequel/plugins/prepared_statements_associations.rb +1 -1
  92. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  93. data/lib/sequel/plugins/serialization.rb +6 -1
  94. data/lib/sequel/plugins/sharding.rb +0 -5
  95. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  96. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  97. data/lib/sequel/plugins/update_primary_key.rb +1 -1
  98. data/lib/sequel/timezones.rb +42 -42
  99. data/lib/sequel/version.rb +1 -1
  100. data/spec/adapters/mssql_spec.rb +29 -29
  101. data/spec/adapters/mysql_spec.rb +86 -104
  102. data/spec/adapters/oracle_spec.rb +48 -76
  103. data/spec/adapters/postgres_spec.rb +98 -33
  104. data/spec/adapters/spec_helper.rb +0 -5
  105. data/spec/adapters/sqlite_spec.rb +24 -21
  106. data/spec/core/connection_pool_spec.rb +9 -15
  107. data/spec/core/core_sql_spec.rb +20 -31
  108. data/spec/core/database_spec.rb +491 -227
  109. data/spec/core/dataset_spec.rb +638 -1051
  110. data/spec/core/expression_filters_spec.rb +0 -1
  111. data/spec/core/mock_adapter_spec.rb +378 -0
  112. data/spec/core/object_graph_spec.rb +48 -114
  113. data/spec/core/schema_generator_spec.rb +3 -3
  114. data/spec/core/schema_spec.rb +51 -114
  115. data/spec/core/spec_helper.rb +3 -90
  116. data/spec/extensions/class_table_inheritance_spec.rb +1 -1
  117. data/spec/extensions/dataset_associations_spec.rb +199 -0
  118. data/spec/extensions/instance_hooks_spec.rb +71 -0
  119. data/spec/extensions/named_timezones_spec.rb +22 -2
  120. data/spec/extensions/nested_attributes_spec.rb +3 -0
  121. data/spec/extensions/schema_spec.rb +1 -1
  122. data/spec/extensions/serialization_modification_detection_spec.rb +1 -0
  123. data/spec/extensions/serialization_spec.rb +5 -8
  124. data/spec/extensions/spec_helper.rb +4 -0
  125. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  126. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  127. data/spec/integration/associations_test.rb +123 -12
  128. data/spec/integration/dataset_test.rb +140 -47
  129. data/spec/integration/eager_loader_test.rb +19 -21
  130. data/spec/integration/model_test.rb +80 -1
  131. data/spec/integration/plugin_test.rb +179 -128
  132. data/spec/integration/prepared_statement_test.rb +92 -91
  133. data/spec/integration/schema_test.rb +42 -23
  134. data/spec/integration/spec_helper.rb +25 -31
  135. data/spec/integration/timezone_test.rb +38 -12
  136. data/spec/integration/transaction_test.rb +161 -34
  137. data/spec/integration/type_test.rb +3 -3
  138. data/spec/model/association_reflection_spec.rb +83 -7
  139. data/spec/model/associations_spec.rb +393 -676
  140. data/spec/model/base_spec.rb +186 -116
  141. data/spec/model/dataset_methods_spec.rb +7 -27
  142. data/spec/model/eager_loading_spec.rb +343 -867
  143. data/spec/model/hooks_spec.rb +160 -79
  144. data/spec/model/model_spec.rb +118 -165
  145. data/spec/model/plugins_spec.rb +7 -13
  146. data/spec/model/record_spec.rb +138 -207
  147. data/spec/model/spec_helper.rb +10 -73
  148. metadata +14 -8
@@ -10,93 +10,6 @@ if ENV['SEQUEL_COLUMNS_INTROSPECTION']
10
10
  Sequel::Dataset.introspect_all_columns
11
11
  end
12
12
 
13
- class MockDataset < Sequel::Dataset
14
- def insert(*args)
15
- @db.execute insert_sql(*args)
16
- end
17
-
18
- def update(*args)
19
- @db.execute update_sql(*args)
20
- end
21
-
22
- def fetch_rows(sql)
23
- @db.execute(sql)
24
- yield({:id => 1, :x => 1})
25
- end
26
-
27
- def quoted_identifier(c)
28
- "\"#{c}\""
29
- end
30
- end
31
-
32
- class MockDatabase < Sequel::Database
33
- set_adapter_scheme :mock
34
- @@quote_identifiers = false
35
- self.identifier_input_method = nil
36
- self.identifier_output_method = nil
37
- attr_reader :sqls
38
-
39
- def execute(sql, opts={})
40
- @sqls ||= []
41
- @sqls << sql
42
- end
43
-
44
- def reset
45
- @sqls = []
46
- end
47
-
48
- def transaction(opts={}); yield; end
49
-
50
- def dataset; MockDataset.new(self); end
51
- end
52
-
53
- class SchemaDummyDatabase < Sequel::Database
54
- attr_reader :sqls
55
- self.identifier_input_method = nil
56
- self.identifier_output_method = nil
57
-
58
- def execute(sql, opts={})
59
- @sqls ||= []
60
- @sqls << sql
61
- end
62
- end
63
-
64
- class DummyDataset < Sequel::Dataset
65
- def first
66
- raise if @opts[:from] == [:a]
67
- true
68
- end
69
- end
70
-
71
- class DummyDatabase < Sequel::Database
72
- attr_reader :sqls
73
-
74
- def execute(sql, opts={})
75
- @sqls ||= []
76
- @sqls << sql
77
- end
78
-
79
- def transaction; yield; end
80
-
81
- def dataset
82
- DummyDataset.new(self)
83
- end
84
- end
85
-
86
- class Dummy2Database < Sequel::Database
87
- attr_reader :sql
88
- def execute(sql); @sql = sql; end
89
- def transaction; yield; end
90
- end
91
-
92
- class DummyDataset < Sequel::Dataset
93
- VALUES = [
94
- {:a => 1, :b => 2},
95
- {:a => 3, :b => 4},
96
- {:a => 5, :b => 6}
97
- ]
98
- def fetch_rows(sql, &block)
99
- VALUES.each(&block)
100
- end
101
- end
102
-
13
+ Sequel.quote_identifiers = false
14
+ Sequel.identifier_input_method = nil
15
+ Sequel.identifier_output_method = nil
@@ -8,7 +8,7 @@ describe "class_table_inheritance plugin" do
8
8
  :managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer}]],
9
9
  :executives=>[[:id, {:type=>:integer}], [:num_managers, {:type=>:integer}]],
10
10
  :staff=>[[:id, {:type=>:integer}], [:manager_id, {:type=>:integer}]],
11
- }[table]
11
+ }[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
12
12
  end
13
13
  def db.dataset(*args)
14
14
  ds = super(*args)
@@ -0,0 +1,199 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "Sequel::Plugins::DatasetAssociations" do
4
+ before do
5
+ @db = Sequel::Database.new
6
+ @Base = Class.new(Sequel::Model)
7
+ @Base.plugin :dataset_associations
8
+
9
+ @Artist = Class.new(@Base)
10
+ @Album = Class.new(@Base)
11
+ @Tag = Class.new(@Base)
12
+
13
+ @Artist.meta_def(:name){'Artist'}
14
+ @Album.meta_def(:name){'Album'}
15
+ @Tag.meta_def(:name){'Tag'}
16
+
17
+ @Artist.dataset = @db[:artists]
18
+ @Album.dataset = @db[:albums]
19
+ @Tag.dataset = @db[:tags]
20
+
21
+ @Artist.columns :id, :name
22
+ @Album.columns :id, :name, :artist_id
23
+ @Tag.columns :id, :name
24
+
25
+ @Artist.plugin :many_through_many
26
+ @Artist.one_to_many :albums, :class=>@Album
27
+ @Artist.one_to_one :first_album, :class=>@Album
28
+ @Album.many_to_one :artist, :class=>@Artist
29
+ @Album.many_to_many :tags, :class=>@Tag
30
+ @Tag.many_to_many :albums, :class=>@Album
31
+ @Artist.many_through_many :tags, [[:albums, :artist_id, :id], [:albums_tags, :album_id, :tag_id]], :class=>@Tag
32
+ end
33
+
34
+ it "should work for many_to_one associations" do
35
+ ds = @Album.artists
36
+ ds.should be_a_kind_of(Sequel::Dataset)
37
+ ds.model.should == @Artist
38
+ ds.sql.should == "SELECT * FROM artists WHERE (artists.id IN (SELECT albums.artist_id FROM albums))"
39
+ end
40
+
41
+ it "should work for one_to_many associations" do
42
+ ds = @Artist.albums
43
+ ds.should be_a_kind_of(Sequel::Dataset)
44
+ ds.model.should == @Album
45
+ ds.sql.should == "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists))"
46
+ end
47
+
48
+ it "should work for one_to_one associations" do
49
+ ds = @Artist.first_albums
50
+ ds.should be_a_kind_of(Sequel::Dataset)
51
+ ds.model.should == @Album
52
+ ds.sql.should == "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists))"
53
+ end
54
+
55
+ it "should work for many_to_many associations" do
56
+ ds = @Album.tags
57
+ ds.should be_a_kind_of(Sequel::Dataset)
58
+ ds.model.should == @Tag
59
+ ds.sql.should == "SELECT tags.* FROM tags WHERE (tags.id IN (SELECT albums_tags.tag_id FROM albums INNER JOIN albums_tags ON (albums_tags.album_id = albums.id)))"
60
+ end
61
+
62
+ it "should work for many_through_many associations" do
63
+ ds = @Artist.tags
64
+ ds.should be_a_kind_of(Sequel::Dataset)
65
+ ds.model.should == @Tag
66
+ ds.sql.should == "SELECT tags.* FROM tags WHERE (tags.id IN (SELECT albums_tags.tag_id FROM artists INNER JOIN albums ON (albums.artist_id = artists.id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id)))"
67
+ end
68
+
69
+ it "should have an associated method that takes an association symbol" do
70
+ ds = @Album.associated(:artist)
71
+ ds.should be_a_kind_of(Sequel::Dataset)
72
+ ds.model.should == @Artist
73
+ ds.sql.should == "SELECT * FROM artists WHERE (artists.id IN (SELECT albums.artist_id FROM albums))"
74
+ end
75
+
76
+ it "should raise an Error if an invalid association is given to associated" do
77
+ proc{@Album.associated(:foo)}.should raise_error(Sequel::Error)
78
+ end
79
+
80
+ it "should raise an Error if an unrecognized association type is used" do
81
+ @Album.association_reflection(:artist)[:type] = :foo
82
+ proc{@Album.artists}.should raise_error(Sequel::Error)
83
+ end
84
+
85
+ it "should work correctly when chaining" do
86
+ ds = @Artist.albums.tags
87
+ ds.should be_a_kind_of(Sequel::Dataset)
88
+ ds.model.should == @Tag
89
+ ds.sql.should == "SELECT tags.* FROM tags WHERE (tags.id IN (SELECT albums_tags.tag_id FROM albums INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE (albums.artist_id IN (SELECT artists.id FROM artists))))"
90
+ end
91
+
92
+ it "should deal correctly with filters before the association method" do
93
+ @Artist.filter(:id=>1).albums.sql.should == "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists WHERE (id = 1)))"
94
+ end
95
+
96
+ it "should deal correctly with filters after the association method" do
97
+ @Artist.albums.filter(:id=>1).sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id = 1))"
98
+ end
99
+
100
+ it "should deal correctly with block on the association" do
101
+ @Artist.one_to_many :albums, :clone=>:albums do |ds| ds.filter(:id=>1..100) end
102
+ @Artist.albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id >= 1) AND (id <= 100))"
103
+ end
104
+
105
+ it "should deal correctly with :conditions option on the association" do
106
+ @Artist.one_to_many :albums, :clone=>:albums, :conditions=>{:id=>1..100}
107
+ @Artist.albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id >= 1) AND (id <= 100))"
108
+ end
109
+
110
+ it "should deal correctly with :distinct option on the association" do
111
+ @Artist.one_to_many :albums, :clone=>:albums, :distinct=>true
112
+ @Artist.albums.sql.should == "SELECT DISTINCT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists))"
113
+ end
114
+
115
+ it "should deal correctly with :eager option on the association" do
116
+ @Artist.one_to_many :albums, :clone=>:albums, :eager=>:tags
117
+ @Artist.albums.opts[:eager].should == {:tags=>nil}
118
+ end
119
+
120
+ it "should deal correctly with :eager_block option on the association, ignoring the association block" do
121
+ @Artist.one_to_many :albums, :clone=>:albums, :eager_block=>proc{|ds| ds.filter(:id=>1..100)} do |ds| ds.filter(:id=>2..200) end
122
+ @Artist.albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id >= 1) AND (id <= 100))"
123
+ end
124
+
125
+ it "should deal correctly with :extend option on the association" do
126
+ @Artist.one_to_many :albums, :clone=>:albums, :extend=>Module.new{def foo(x) filter(:id=>x) end}
127
+ @Artist.albums.foo(1).sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id = 1))"
128
+ end
129
+
130
+ it "should deal correctly with :order option on the association" do
131
+ @Artist.one_to_many :albums, :clone=>:albums, :order=>:name
132
+ @Artist.albums.sql.should == "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists)) ORDER BY name"
133
+ end
134
+
135
+ it "should deal correctly with :select option on the association" do
136
+ @Artist.one_to_many :albums, :clone=>:albums, :select=>[:id, :name]
137
+ @Artist.albums.sql.should == "SELECT id, name FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists))"
138
+ end
139
+ end
140
+
141
+ describe "Sequel::Plugins::DatasetAssociations with composite keys" do
142
+ before do
143
+ @db = Sequel::Database.new
144
+ @Base = Class.new(Sequel::Model)
145
+ @Base.plugin :dataset_associations
146
+
147
+ @Artist = Class.new(@Base)
148
+ @Album = Class.new(@Base)
149
+ @Tag = Class.new(@Base)
150
+
151
+ @Artist.meta_def(:name){'Artist'}
152
+ @Album.meta_def(:name){'Album'}
153
+ @Tag.meta_def(:name){'Tag'}
154
+
155
+ @Artist.dataset = @db[:artists]
156
+ @Album.dataset = @db[:albums]
157
+ @Tag.dataset = @db[:tags]
158
+
159
+ @Artist.set_primary_key([:id1, :id2])
160
+ @Album.set_primary_key([:id1, :id2])
161
+ @Tag.set_primary_key([:id1, :id2])
162
+
163
+ @Artist.columns :id1, :id2, :name
164
+ @Album.columns :id1, :id2, :name, :artist_id1, :artist_id2
165
+ @Tag.columns :id1, :id2, :name
166
+
167
+ @Artist.plugin :many_through_many
168
+ @Artist.one_to_many :albums, :class=>@Album, :key=>[:artist_id1, :artist_id2]
169
+ @Artist.one_to_one :first_album, :class=>@Album, :key=>[:artist_id1, :artist_id2]
170
+ @Album.many_to_one :artist, :class=>@Artist, :key=>[:artist_id1, :artist_id2]
171
+ @Album.many_to_many :tags, :class=>@Tag, :left_key=>[:album_id1, :album_id2], :right_key=>[:tag_id1, :tag_id2]
172
+ @Tag.many_to_many :albums, :class=>@Album, :right_key=>[:album_id1, :album_id2], :left_key=>[:tag_id1, :tag_id2]
173
+ @Artist.many_through_many :tags, [[:albums, [:artist_id1, :artist_id2], [:id1, :id2]], [:albums_tags, [:album_id1, :album_id2], [:tag_id1, :tag_id2]]], :class=>@Tag
174
+ end
175
+
176
+ it "should work for many_to_one associations" do
177
+ @Album.artists.sql.should == "SELECT * FROM artists WHERE ((artists.id1, artists.id2) IN (SELECT albums.artist_id1, albums.artist_id2 FROM albums))"
178
+ end
179
+
180
+ it "should work for one_to_many associations" do
181
+ @Artist.albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists))"
182
+ end
183
+
184
+ it "should work for one_to_one associations" do
185
+ @Artist.first_albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists))"
186
+ end
187
+
188
+ it "should work for many_to_many associations" do
189
+ @Album.tags.sql.should == "SELECT tags.* FROM tags WHERE ((tags.id1, tags.id2) IN (SELECT albums_tags.tag_id1, albums_tags.tag_id2 FROM albums INNER JOIN albums_tags ON ((albums_tags.album_id1 = albums.id1) AND (albums_tags.album_id2 = albums.id2))))"
190
+ end
191
+
192
+ it "should work for many_through_many associations" do
193
+ @Artist.tags.sql.should == "SELECT tags.* FROM tags WHERE ((tags.id1, tags.id2) IN (SELECT albums_tags.tag_id1, albums_tags.tag_id2 FROM artists INNER JOIN albums ON ((albums.artist_id1 = artists.id1) AND (albums.artist_id2 = artists.id2)) INNER JOIN albums_tags ON ((albums_tags.album_id1 = albums.id1) AND (albums_tags.album_id2 = albums.id2))))"
194
+ end
195
+
196
+ it "should work correctly when chaining" do
197
+ @Artist.albums.tags.sql.should == "SELECT tags.* FROM tags WHERE ((tags.id1, tags.id2) IN (SELECT albums_tags.tag_id1, albums_tags.tag_id2 FROM albums INNER JOIN albums_tags ON ((albums_tags.album_id1 = albums.id1) AND (albums_tags.album_id2 = albums.id2)) WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists))))"
198
+ end
199
+ end
@@ -177,3 +177,74 @@ describe "InstanceHooks plugin" do
177
177
  @r.should == [2, 1, 4, 3]
178
178
  end
179
179
  end
180
+
181
+ describe "InstanceHooks plugin with transactions" do
182
+ before do
183
+ @logger = Object.new
184
+ def @logger.method_missing(meth, sql)
185
+ (@sqls ||= []) << sql
186
+ end
187
+ def @logger.sqls
188
+ @sqls
189
+ end
190
+ @db = Class.new(Sequel::Database) do
191
+ def connect(*)
192
+ Object.new
193
+ end
194
+ def log_connection_execute(conn, sql)
195
+ execute(sql)
196
+ end
197
+ def execute(sql, opts={})
198
+ @loggers.each{|l| l.info(sql)}
199
+ end
200
+ end.new(:loggers=>[@logger])
201
+ pr = proc{|x| r(x)}
202
+ @c = Class.new(Sequel::Model(@db[:items])) do
203
+ attr_accessor :rb
204
+ def _delete
205
+ end
206
+ def after_save
207
+ db.execute('as')
208
+ raise Sequel::Rollback if rb
209
+ end
210
+ def after_destroy
211
+ db.execute('ad')
212
+ raise Sequel::Rollback if rb
213
+ end
214
+ end
215
+ @c.use_transactions = true
216
+ @c.plugin :instance_hooks
217
+ @o = @c.load({:id=>1})
218
+ @or = @c.load({:id=>1})
219
+ @or.rb = true
220
+ @r = []
221
+ end
222
+
223
+ it "should support after_commit_hook" do
224
+ @o.after_commit_hook{@db.execute('ac1')}
225
+ @o.after_commit_hook{@db.execute('ac2')}
226
+ @o.save.should_not be_nil
227
+ @logger.sqls.should == ['BEGIN', 'as', 'COMMIT', 'ac1', 'ac2']
228
+ end
229
+
230
+ it "should support after_rollback_hook" do
231
+ @or.after_rollback_hook{@db.execute('ar1')}
232
+ @or.after_rollback_hook{@db.execute('ar2')}
233
+ @or.save.should be_nil
234
+ @logger.sqls.should == ['BEGIN', 'as', 'ROLLBACK', 'ar1', 'ar2']
235
+ end
236
+
237
+ it "should support after_commit_hook" do
238
+ @o.after_destroy_commit_hook{@db.execute('adc1')}
239
+ @o.after_destroy_commit_hook{@db.execute('adc2')}
240
+ @o.destroy.should_not be_nil
241
+ @logger.sqls.should == ['BEGIN', 'ad', 'COMMIT', 'adc1', 'adc2']
242
+ end
243
+
244
+ it "should support after_rollback_hook" do
245
+ @or.after_destroy_rollback_hook{@db.execute('adr1')}
246
+ @or.after_destroy_rollback_hook{@db.execute('adr2')}
247
+ @or.destroy.should be_nil
248
+ @logger.sqls.should == ['BEGIN', 'ad', 'ROLLBACK', 'adr1', 'adr2']
249
+ end
250
+ end
@@ -66,8 +66,28 @@ describe "Sequel named_timezones extension" do
66
66
  end
67
67
 
68
68
  it "should work with the thread_local_timezones extension" do
69
- [Thread.new{Sequel.thread_application_timezone = 'America/New_York'; sleep 0.03; Sequel.application_timezone.should == @tz_out},
70
- Thread.new{sleep 0.01; Sequel.thread_application_timezone = 'America/Los_Angeles'; sleep 0.01; Sequel.application_timezone.should == @tz_in}].each{|x| x.join}
69
+ q, q1, q2 = Queue.new, Queue.new, Queue.new
70
+ tz1, tz2 = nil, nil
71
+ t1 = Thread.new do
72
+ Sequel.thread_application_timezone = 'America/New_York'
73
+ q2.push nil
74
+ q.pop
75
+ tz1 = Sequel.application_timezone
76
+ end
77
+ t2 = Thread.new do
78
+ Sequel.thread_application_timezone = 'America/Los_Angeles'
79
+ q2.push nil
80
+ q1.pop
81
+ tz2 = Sequel.application_timezone
82
+ end
83
+ q2.pop
84
+ q2.pop
85
+ q.push nil
86
+ q1.push nil
87
+ t1.join
88
+ t2.join
89
+ tz1.should == @tz_out
90
+ tz2.should == @tz_in
71
91
  end
72
92
  end
73
93
  end
@@ -29,6 +29,9 @@ describe "NestedAttributes plugin" do
29
29
  end
30
30
  end
31
31
  db = Sequel::Database.new({})
32
+ def db.connect(opts)
33
+ Object.new
34
+ end
32
35
  db.meta_def(:dataset) do |*a|
33
36
  x = super(*a)
34
37
  x.extend(ds_mod)
@@ -57,7 +57,7 @@ describe Sequel::Model, "create_table and schema" do
57
57
 
58
58
  it "should reload the schema from the database" do
59
59
  schem = {:name=>{:type=>:string}, :price=>{:type=>:float}}
60
- @model.db.should_receive(:schema).with(:items, :reload=>true).and_return(schem.to_a.sort_by{|x| x[0].to_s})
60
+ @model.db.should_receive(:schema).with(@model.dataset, :reload=>true).and_return(schem.to_a.sort_by{|x| x[0].to_s})
61
61
  @model.create_table
62
62
  @model.db_schema.should == schem
63
63
  @model.instance_variable_get(:@columns).should == [:name, :price]
@@ -1,4 +1,5 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+ require 'yaml'
2
3
 
3
4
  describe "serialization_modification_detection plugin" do
4
5
  before do
@@ -22,11 +22,11 @@ describe "Serialization plugin" do
22
22
  it "should allow setting additional serializable attributes via plugin :serialization call" do
23
23
  @c.plugin :serialization, :yaml, :abc
24
24
  @c.create(:abc => 1, :def=> 2)
25
- MODEL_DB.sqls.last.should =~ /INSERT INTO items \((abc, def|def, abc)\) VALUES \(('--- 1\n', 2|2, '--- 1\n')\)/
25
+ MODEL_DB.sqls.last.should =~ /INSERT INTO items \((abc, def|def, abc)\) VALUES \(('--- 1\n(\.\.\.\n)?', 2|2, '--- 1\n(\.\.\.\n)?')\)/
26
26
 
27
27
  @c.plugin :serialization, :marshal, :def
28
28
  @c.create(:abc => 1, :def=> 1)
29
- MODEL_DB.sqls.last.should =~ /INSERT INTO items \((abc, def|def, abc)\) VALUES \(('--- 1\n', 'BAhpBg==\n'|'BAhpBg==\n', '--- 1\n')\)/
29
+ MODEL_DB.sqls.last.should =~ /INSERT INTO items \((abc, def|def, abc)\) VALUES \(('--- 1\n(\.\.\.\n)?', 'BAhpBg==\n'|'BAhpBg==\n', '--- 1\n(\.\.\.\n)?')\)/
30
30
 
31
31
  @c.plugin :serialization, :json, :ghi
32
32
  @c.create(:ghi => [123])
@@ -38,10 +38,7 @@ describe "Serialization plugin" do
38
38
  @c.create(:abc => 1)
39
39
  @c.create(:abc => "hello")
40
40
 
41
- MODEL_DB.sqls.should == [ \
42
- "INSERT INTO items (abc) VALUES ('--- 1\n')", \
43
- "INSERT INTO items (abc) VALUES ('--- hello\n')", \
44
- ]
41
+ MODEL_DB.sqls.map{|s| s.sub("...\n", '')}.should == ["INSERT INTO items (abc) VALUES ('--- 1\n')", "INSERT INTO items (abc) VALUES ('--- hello\n')"]
45
42
  end
46
43
 
47
44
  it "serialization_format should be the serialization format used" do
@@ -97,7 +94,7 @@ describe "Serialization plugin" do
97
94
 
98
95
  o.update(:abc => 23)
99
96
  @c.create(:abc => [1, 2, 3])
100
- MODEL_DB.sqls.should == ["UPDATE items SET abc = '--- 23\n' WHERE (id = 1)",
97
+ MODEL_DB.sqls.should == ["UPDATE items SET abc = '#{23.to_yaml}' WHERE (id = 1)",
101
98
  "INSERT INTO items (abc) VALUES ('#{[1, 2, 3].to_yaml}')"]
102
99
  end
103
100
 
@@ -164,7 +161,7 @@ describe "Serialization plugin" do
164
161
 
165
162
  o.update(:abc => 23)
166
163
  Class.new(@c).create(:abc => [1, 2, 3])
167
- MODEL_DB.sqls.should == ["UPDATE items SET abc = '--- 23\n' WHERE (id = 1)",
164
+ MODEL_DB.sqls.should == ["UPDATE items SET abc = '#{23.to_yaml}' WHERE (id = 1)",
168
165
  "INSERT INTO items (abc) VALUES ('#{[1, 2, 3].to_yaml}')"]
169
166
  end
170
167