sequel 3.21.0 → 3.32.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 (234) hide show
  1. data/CHANGELOG +539 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +20 -6
  4. data/Rakefile +37 -19
  5. data/bin/sequel +1 -5
  6. data/doc/advanced_associations.rdoc +17 -0
  7. data/doc/association_basics.rdoc +293 -43
  8. data/doc/dataset_basics.rdoc +4 -4
  9. data/doc/dataset_filtering.rdoc +8 -0
  10. data/doc/mass_assignment.rdoc +54 -0
  11. data/doc/migration.rdoc +15 -538
  12. data/doc/model_hooks.rdoc +72 -27
  13. data/doc/opening_databases.rdoc +89 -50
  14. data/doc/prepared_statements.rdoc +40 -13
  15. data/doc/reflection.rdoc +8 -2
  16. data/doc/release_notes/3.22.0.txt +39 -0
  17. data/doc/release_notes/3.23.0.txt +172 -0
  18. data/doc/release_notes/3.24.0.txt +420 -0
  19. data/doc/release_notes/3.25.0.txt +88 -0
  20. data/doc/release_notes/3.26.0.txt +88 -0
  21. data/doc/release_notes/3.27.0.txt +82 -0
  22. data/doc/release_notes/3.28.0.txt +304 -0
  23. data/doc/release_notes/3.29.0.txt +459 -0
  24. data/doc/release_notes/3.30.0.txt +135 -0
  25. data/doc/release_notes/3.31.0.txt +146 -0
  26. data/doc/release_notes/3.32.0.txt +202 -0
  27. data/doc/schema_modification.rdoc +547 -0
  28. data/doc/sharding.rdoc +7 -1
  29. data/doc/testing.rdoc +129 -0
  30. data/doc/transactions.rdoc +137 -0
  31. data/doc/virtual_rows.rdoc +2 -2
  32. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  33. data/lib/sequel/adapters/ado.rb +40 -18
  34. data/lib/sequel/adapters/amalgalite.rb +17 -9
  35. data/lib/sequel/adapters/db2.rb +175 -86
  36. data/lib/sequel/adapters/dbi.rb +15 -15
  37. data/lib/sequel/adapters/do/mysql.rb +5 -7
  38. data/lib/sequel/adapters/do/postgres.rb +0 -5
  39. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  40. data/lib/sequel/adapters/do.rb +17 -36
  41. data/lib/sequel/adapters/firebird.rb +27 -208
  42. data/lib/sequel/adapters/ibmdb.rb +448 -0
  43. data/lib/sequel/adapters/informix.rb +6 -23
  44. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  45. data/lib/sequel/adapters/jdbc/db2.rb +52 -0
  46. data/lib/sequel/adapters/jdbc/derby.rb +260 -0
  47. data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
  48. data/lib/sequel/adapters/jdbc/h2.rb +66 -30
  49. data/lib/sequel/adapters/jdbc/hsqldb.rb +177 -0
  50. data/lib/sequel/adapters/jdbc/informix.rb +26 -0
  51. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  52. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  53. data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
  54. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  55. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
  56. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
  57. data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
  58. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  59. data/lib/sequel/adapters/jdbc.rb +231 -78
  60. data/lib/sequel/adapters/mock.rb +339 -0
  61. data/lib/sequel/adapters/mysql.rb +85 -184
  62. data/lib/sequel/adapters/mysql2.rb +26 -25
  63. data/lib/sequel/adapters/odbc/db2.rb +17 -0
  64. data/lib/sequel/adapters/odbc/mssql.rb +1 -6
  65. data/lib/sequel/adapters/odbc.rb +28 -9
  66. data/lib/sequel/adapters/openbase.rb +3 -5
  67. data/lib/sequel/adapters/oracle.rb +355 -53
  68. data/lib/sequel/adapters/postgres.rb +194 -33
  69. data/lib/sequel/adapters/shared/access.rb +32 -9
  70. data/lib/sequel/adapters/shared/db2.rb +328 -0
  71. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  72. data/lib/sequel/adapters/shared/informix.rb +53 -0
  73. data/lib/sequel/adapters/shared/mssql.rb +278 -107
  74. data/lib/sequel/adapters/shared/mysql.rb +203 -65
  75. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
  76. data/lib/sequel/adapters/shared/oracle.rb +237 -46
  77. data/lib/sequel/adapters/shared/postgres.rb +214 -82
  78. data/lib/sequel/adapters/shared/progress.rb +5 -8
  79. data/lib/sequel/adapters/shared/sqlite.rb +200 -50
  80. data/lib/sequel/adapters/sqlite.rb +29 -21
  81. data/lib/sequel/adapters/swift/mysql.rb +12 -7
  82. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  83. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  84. data/lib/sequel/adapters/swift.rb +5 -5
  85. data/lib/sequel/adapters/tinytds.rb +160 -19
  86. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  87. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  88. data/lib/sequel/ast_transformer.rb +190 -0
  89. data/lib/sequel/connection_pool/threaded.rb +3 -2
  90. data/lib/sequel/connection_pool.rb +1 -1
  91. data/lib/sequel/core.rb +68 -5
  92. data/lib/sequel/database/connecting.rb +5 -6
  93. data/lib/sequel/database/dataset.rb +4 -4
  94. data/lib/sequel/database/dataset_defaults.rb +59 -1
  95. data/lib/sequel/database/logging.rb +1 -1
  96. data/lib/sequel/database/misc.rb +104 -19
  97. data/lib/sequel/database/query.rb +163 -59
  98. data/lib/sequel/database/schema_generator.rb +17 -7
  99. data/lib/sequel/database/schema_methods.rb +59 -29
  100. data/lib/sequel/dataset/actions.rb +240 -76
  101. data/lib/sequel/dataset/features.rb +91 -8
  102. data/lib/sequel/dataset/graph.rb +38 -11
  103. data/lib/sequel/dataset/misc.rb +50 -23
  104. data/lib/sequel/dataset/mutation.rb +12 -7
  105. data/lib/sequel/dataset/prepared_statements.rb +59 -27
  106. data/lib/sequel/dataset/query.rb +236 -43
  107. data/lib/sequel/dataset/sql.rb +676 -267
  108. data/lib/sequel/dataset.rb +8 -0
  109. data/lib/sequel/exceptions.rb +4 -0
  110. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  111. data/lib/sequel/extensions/migration.rb +6 -4
  112. data/lib/sequel/extensions/named_timezones.rb +5 -0
  113. data/lib/sequel/extensions/query.rb +1 -1
  114. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  115. data/lib/sequel/extensions/to_dot.rb +95 -83
  116. data/lib/sequel/model/associations.rb +1081 -344
  117. data/lib/sequel/model/base.rb +420 -133
  118. data/lib/sequel/model/errors.rb +1 -1
  119. data/lib/sequel/model/exceptions.rb +5 -1
  120. data/lib/sequel/model.rb +20 -10
  121. data/lib/sequel/plugins/active_model.rb +13 -1
  122. data/lib/sequel/plugins/association_pks.rb +22 -4
  123. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  124. data/lib/sequel/plugins/composition.rb +43 -10
  125. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  126. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  127. data/lib/sequel/plugins/force_encoding.rb +6 -6
  128. data/lib/sequel/plugins/identity_map.rb +114 -7
  129. data/lib/sequel/plugins/many_through_many.rb +68 -7
  130. data/lib/sequel/plugins/nested_attributes.rb +65 -10
  131. data/lib/sequel/plugins/prepared_statements.rb +151 -0
  132. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  133. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  134. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  135. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  136. data/lib/sequel/plugins/serialization.rb +98 -49
  137. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  138. data/lib/sequel/plugins/sharding.rb +21 -54
  139. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  140. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  141. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  142. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  143. data/lib/sequel/sql.rb +109 -52
  144. data/lib/sequel/timezones.rb +57 -38
  145. data/lib/sequel/version.rb +1 -1
  146. data/spec/adapters/db2_spec.rb +146 -0
  147. data/spec/adapters/mssql_spec.rb +135 -30
  148. data/spec/adapters/mysql_spec.rb +244 -212
  149. data/spec/adapters/oracle_spec.rb +67 -77
  150. data/spec/adapters/postgres_spec.rb +267 -78
  151. data/spec/adapters/spec_helper.rb +6 -5
  152. data/spec/adapters/sqlite_spec.rb +35 -21
  153. data/spec/core/connection_pool_spec.rb +71 -92
  154. data/spec/core/core_sql_spec.rb +21 -30
  155. data/spec/core/database_spec.rb +789 -512
  156. data/spec/core/dataset_spec.rb +1176 -1061
  157. data/spec/core/expression_filters_spec.rb +159 -42
  158. data/spec/core/mock_adapter_spec.rb +419 -0
  159. data/spec/core/object_graph_spec.rb +86 -114
  160. data/spec/core/schema_generator_spec.rb +3 -3
  161. data/spec/core/schema_spec.rb +298 -38
  162. data/spec/core/spec_helper.rb +6 -48
  163. data/spec/extensions/active_model_spec.rb +13 -0
  164. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  165. data/spec/extensions/association_dependencies_spec.rb +2 -12
  166. data/spec/extensions/association_pks_spec.rb +66 -32
  167. data/spec/extensions/caching_spec.rb +23 -50
  168. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  169. data/spec/extensions/columns_introspection_spec.rb +91 -0
  170. data/spec/extensions/composition_spec.rb +18 -13
  171. data/spec/extensions/dataset_associations_spec.rb +199 -0
  172. data/spec/extensions/defaults_setter_spec.rb +64 -0
  173. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  174. data/spec/extensions/identity_map_spec.rb +114 -22
  175. data/spec/extensions/instance_filters_spec.rb +11 -21
  176. data/spec/extensions/instance_hooks_spec.rb +53 -0
  177. data/spec/extensions/json_serializer_spec.rb +4 -5
  178. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  179. data/spec/extensions/list_spec.rb +17 -39
  180. data/spec/extensions/many_through_many_spec.rb +283 -250
  181. data/spec/extensions/migration_spec.rb +35 -32
  182. data/spec/extensions/named_timezones_spec.rb +23 -3
  183. data/spec/extensions/nested_attributes_spec.rb +97 -88
  184. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  185. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  186. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  187. data/spec/extensions/prepared_statements_spec.rb +53 -0
  188. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  189. data/spec/extensions/pretty_table_spec.rb +1 -6
  190. data/spec/extensions/query_spec.rb +6 -0
  191. data/spec/extensions/rcte_tree_spec.rb +41 -43
  192. data/spec/extensions/schema_dumper_spec.rb +5 -8
  193. data/spec/extensions/schema_spec.rb +13 -21
  194. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  195. data/spec/extensions/serialization_spec.rb +81 -43
  196. data/spec/extensions/sharding_spec.rb +66 -140
  197. data/spec/extensions/single_table_inheritance_spec.rb +18 -29
  198. data/spec/extensions/spec_helper.rb +13 -61
  199. data/spec/extensions/sql_expr_spec.rb +20 -60
  200. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  201. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  202. data/spec/extensions/timestamps_spec.rb +6 -6
  203. data/spec/extensions/to_dot_spec.rb +4 -7
  204. data/spec/extensions/touch_spec.rb +13 -14
  205. data/spec/extensions/tree_spec.rb +11 -26
  206. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  207. data/spec/extensions/update_primary_key_spec.rb +30 -24
  208. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  209. data/spec/extensions/validation_helpers_spec.rb +16 -35
  210. data/spec/extensions/xml_serializer_spec.rb +16 -4
  211. data/spec/integration/associations_test.rb +661 -21
  212. data/spec/integration/database_test.rb +4 -2
  213. data/spec/integration/dataset_test.rb +500 -67
  214. data/spec/integration/eager_loader_test.rb +19 -21
  215. data/spec/integration/model_test.rb +80 -1
  216. data/spec/integration/plugin_test.rb +367 -119
  217. data/spec/integration/prepared_statement_test.rb +222 -125
  218. data/spec/integration/schema_test.rb +217 -39
  219. data/spec/integration/spec_helper.rb +39 -30
  220. data/spec/integration/timezone_test.rb +38 -12
  221. data/spec/integration/transaction_test.rb +182 -5
  222. data/spec/integration/type_test.rb +17 -3
  223. data/spec/model/association_reflection_spec.rb +201 -7
  224. data/spec/model/associations_spec.rb +955 -662
  225. data/spec/model/base_spec.rb +275 -95
  226. data/spec/model/dataset_methods_spec.rb +7 -27
  227. data/spec/model/eager_loading_spec.rb +677 -676
  228. data/spec/model/hooks_spec.rb +349 -67
  229. data/spec/model/model_spec.rb +222 -168
  230. data/spec/model/plugins_spec.rb +24 -13
  231. data/spec/model/record_spec.rb +381 -218
  232. data/spec/model/spec_helper.rb +13 -71
  233. data/spec/model/validations_spec.rb +11 -0
  234. metadata +117 -73
@@ -0,0 +1,91 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
+
3
+ describe "Sequel::Dataset.introspect_all_columns" do
4
+ before do
5
+ @db = MODEL_DB
6
+ @ds = @db[:a]
7
+ class Sequel::Dataset
8
+ # Handle case where introspect_all_columns has already been called
9
+ alias columns columns_without_introspection unless instance_methods(false).map{|x| x.to_s}.include?('columns')
10
+ end
11
+ Sequel::Dataset.introspect_all_columns
12
+ @db.reset
13
+ end
14
+ after do
15
+ class Sequel::Dataset
16
+ alias columns columns_without_introspection
17
+ end
18
+ end
19
+
20
+ specify "should turn on column introspection by default" do
21
+ @ds.select(:x).columns.should == [:x]
22
+ @db.sqls.length.should == 0
23
+ end
24
+ end
25
+
26
+ describe "columns_introspection extension" do
27
+ before do
28
+ @db = MODEL_DB
29
+ @ds = @db[:a]
30
+ @ds.extend(Sequel::ColumnsIntrospection.dup) # dup to allow multiple places in class hierarchy
31
+ @db.reset
32
+ end
33
+
34
+ specify "should not issue a database query if the columns are already loaded" do
35
+ @ds.instance_variable_set(:@columns, [:x])
36
+ @ds.columns.should == [:x]
37
+ @db.sqls.length.should == 0
38
+ end
39
+
40
+ specify "should handle plain symbols without a database query" do
41
+ @ds.select(:x).columns.should == [:x]
42
+ @db.sqls.length.should == 0
43
+ end
44
+
45
+ specify "should handle qualified symbols without a database query" do
46
+ @ds.select(:t__x).columns.should == [:x]
47
+ @db.sqls.length.should == 0
48
+ end
49
+
50
+ specify "should handle aliased symbols without a database query" do
51
+ @ds.select(:x___a).columns.should == [:a]
52
+ @db.sqls.length.should == 0
53
+ end
54
+
55
+ specify "should handle qualified and aliased symbols without a database query" do
56
+ @ds.select(:t__x___a).columns.should == [:a]
57
+ @db.sqls.length.should == 0
58
+ end
59
+
60
+ specify "should handle SQL::Identifiers " do
61
+ @ds.select(:x.identifier).columns.should == [:x]
62
+ @db.sqls.length.should == 0
63
+ end
64
+
65
+ specify "should handle SQL::QualifiedIdentifiers" do
66
+ @ds.select(:x.qualify(:t)).columns.should == [:x]
67
+ @ds.select(:x.identifier.qualify(:t)).columns.should == [:x]
68
+ @db.sqls.length.should == 0
69
+ end
70
+
71
+ specify "should handle SQL::AliasedExpressions" do
72
+ @ds.select(:x.as(:a)).columns.should == [:a]
73
+ @ds.select(:x.as(:a.identifier)).columns.should == [:a]
74
+ @db.sqls.length.should == 0
75
+ end
76
+
77
+ specify "should issue a database query if the wildcard is selected" do
78
+ @ds.columns
79
+ @db.sqls.length.should == 1
80
+ end
81
+
82
+ specify "should issue a database query if an unsupported type is used" do
83
+ @ds.select(1).columns
84
+ @db.sqls.length.should == 1
85
+ end
86
+
87
+ specify "should not have column introspection on by default" do
88
+ @db[:a].select(:x).columns
89
+ @db.sqls.length.should == 1
90
+ end
91
+ end
@@ -48,9 +48,10 @@ describe "Composition plugin" do
48
48
  @c.composition :date, :composer=>proc{Date.new(year+1, month+2, day+3)}, :decomposer=>proc{[:year, :month, :day].each{|s| self.send("#{s}=", date.send(s) * 2)}}
49
49
  @o.date.should == Date.new(2, 4, 6)
50
50
  @o.save
51
- MODEL_DB.sqls.last.should include("year = 4")
52
- MODEL_DB.sqls.last.should include("month = 8")
53
- MODEL_DB.sqls.last.should include("day = 12")
51
+ sql = MODEL_DB.sqls.last
52
+ sql.should include("year = 4")
53
+ sql.should include("month = 8")
54
+ sql.should include("day = 12")
54
55
  end
55
56
 
56
57
  it "should allow call super in composition getter and setter method definition in class" do
@@ -139,8 +140,9 @@ describe "Composition plugin" do
139
140
  @o.date.month.should == 6
140
141
  @o.date = c.new(3, 4)
141
142
  @o.save
142
- MODEL_DB.sqls.last.should include("year = 6")
143
- MODEL_DB.sqls.last.should include("month = 12")
143
+ sql = MODEL_DB.sqls.last
144
+ sql.should include("year = 6")
145
+ sql.should include("month = 12")
144
146
  end
145
147
 
146
148
  it ":mapping option should work with an array of two pairs of symbols" do
@@ -160,8 +162,9 @@ describe "Composition plugin" do
160
162
  @o.date.m.should == 6
161
163
  @o.date = c.new(3, 4)
162
164
  @o.save
163
- MODEL_DB.sqls.last.should include("year = 6")
164
- MODEL_DB.sqls.last.should include("month = 12")
165
+ sql = MODEL_DB.sqls.last
166
+ sql.should include("year = 6")
167
+ sql.should include("month = 12")
165
168
  end
166
169
 
167
170
  it ":mapping option :composer should return nil if all values are nil" do
@@ -173,9 +176,10 @@ describe "Composition plugin" do
173
176
  @c.composition :date, :mapping=>[:year, :month, :day]
174
177
  @o.date = nil
175
178
  @o.save
176
- MODEL_DB.sqls.last.should include("year = NULL")
177
- MODEL_DB.sqls.last.should include("month = NULL")
178
- MODEL_DB.sqls.last.should include("day = NULL")
179
+ sql = MODEL_DB.sqls.last
180
+ sql.should include("year = NULL")
181
+ sql.should include("month = NULL")
182
+ sql.should include("day = NULL")
179
183
  end
180
184
 
181
185
  it "should work correctly with subclasses" do
@@ -184,8 +188,9 @@ describe "Composition plugin" do
184
188
  o = c.load(:id=>1, :year=>1, :month=>2, :day=>3)
185
189
  o.date.should == Date.new(1, 2, 3)
186
190
  o.save
187
- MODEL_DB.sqls.last.should include("year = 1")
188
- MODEL_DB.sqls.last.should include("month = 2")
189
- MODEL_DB.sqls.last.should include("day = 3")
191
+ sql = MODEL_DB.sqls.last
192
+ sql.should include("year = 1")
193
+ sql.should include("month = 2")
194
+ sql.should include("day = 3")
190
195
  end
191
196
  end
@@ -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
@@ -0,0 +1,64 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "Sequel::Plugins::DefaultsSetter" do
4
+ before do
5
+ @db = db = Sequel::Database.new
6
+ @c = c = Class.new(Sequel::Model(db[:foo]))
7
+ @c.instance_variable_set(:@db_schema, {:a=>{}})
8
+ @c.plugin :defaults_setter
9
+ @c.columns :a
10
+ @pr = proc{|x| db.meta_def(:schema){|*| [[:a, {:ruby_default => x}]]}; c.dataset = c.dataset; c}
11
+ end
12
+
13
+ it "should set default value upon initialization" do
14
+ @pr.call(2).new.values.should == {:a=>2}
15
+ end
16
+
17
+ it "should not mark the column as modified" do
18
+ @pr.call(2).new.changed_columns.should == []
19
+ end
20
+
21
+ it "should not set a default of nil" do
22
+ @pr.call(nil).new.values.should == {}
23
+ end
24
+
25
+ it "should not override a given value" do
26
+ @pr.call(2)
27
+ @c.new('a'=>3).values.should == {:a=>3}
28
+ @c.new('a'=>nil).values.should == {:a=>nil}
29
+ end
30
+
31
+ it "should work correctly when subclassing" do
32
+ Class.new(@pr.call(2)).new.values.should == {:a=>2}
33
+ end
34
+
35
+ it "should contain the default values in default_values" do
36
+ @pr.call(2).default_values.should == {:a=>2}
37
+ @pr.call(nil).default_values.should == {}
38
+ end
39
+
40
+ it "should allow modifications of default values" do
41
+ @pr.call(2)
42
+ @c.default_values[:a] = 3
43
+ @c.new.values.should == {:a => 3}
44
+ end
45
+
46
+ it "should allow proc default values" do
47
+ @pr.call(2)
48
+ @c.default_values[:a] = proc{3}
49
+ @c.new.values.should == {:a => 3}
50
+ end
51
+
52
+ it "should have procs that set default values set them to nil" do
53
+ @pr.call(2)
54
+ @c.default_values[:a] = proc{nil}
55
+ @c.new.values.should == {:a => nil}
56
+ end
57
+
58
+ it "should work correctly on a model without a dataset" do
59
+ @pr.call(2)
60
+ c = Class.new(Sequel::Model(@db[:bar]))
61
+ c.plugin :defaults_setter
62
+ c.default_values.should == {:a=>2}
63
+ end
64
+ end