sequel 3.28.0 → 3.29.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 (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
@@ -2,15 +2,19 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe Sequel::Model::Associations::AssociationReflection, "#associated_class" do
4
4
  before do
5
- @c = Class.new(Sequel::Model)
5
+ @c = Class.new(Sequel::Model(:foo))
6
6
  class ::ParParent < Sequel::Model; end
7
7
  end
8
+ after do
9
+ Object.send(:remove_const, :ParParent)
10
+ end
8
11
 
9
12
  it "should use the :class value if present" do
10
13
  @c.many_to_one :c, :class=>ParParent
11
14
  @c.association_reflection(:c).keys.should include(:class)
12
15
  @c.association_reflection(:c).associated_class.should == ParParent
13
16
  end
17
+
14
18
  it "should figure out the class if the :class value is not present" do
15
19
  @c.many_to_one :c, :class=>'ParParent'
16
20
  @c.association_reflection(:c).keys.should_not include(:class)
@@ -20,15 +24,19 @@ end
20
24
 
21
25
  describe Sequel::Model::Associations::AssociationReflection, "#primary_key" do
22
26
  before do
23
- @c = Class.new(Sequel::Model)
27
+ @c = Class.new(Sequel::Model(:foo))
24
28
  class ::ParParent < Sequel::Model; end
25
29
  end
30
+ after do
31
+ Object.send(:remove_const, :ParParent)
32
+ end
26
33
 
27
34
  it "should use the :primary_key value if present" do
28
35
  @c.many_to_one :c, :class=>ParParent, :primary_key=>:blah__blah
29
36
  @c.association_reflection(:c).keys.should include(:primary_key)
30
37
  @c.association_reflection(:c).primary_key.should == :blah__blah
31
38
  end
39
+
32
40
  it "should use the associated table's primary key if :primary_key is not present" do
33
41
  @c.many_to_one :c, :class=>'ParParent'
34
42
  @c.association_reflection(:c).keys.should_not include(:primary_key)
@@ -49,8 +57,8 @@ describe Sequel::Model::Associations::AssociationReflection, "#reciprocal" do
49
57
  end
50
58
 
51
59
  it "should use the :reciprocal value if present" do
52
- @c = Class.new(Sequel::Model)
53
- @d = Class.new(Sequel::Model)
60
+ @c = Class.new(Sequel::Model(:foo))
61
+ @d = Class.new(Sequel::Model(:foo))
54
62
  @c.many_to_one :c, :class=>@d, :reciprocal=>:xx
55
63
  @c.association_reflection(:c).keys.should include(:reciprocal)
56
64
  @c.association_reflection(:c).reciprocal.should == :xx
@@ -111,9 +119,12 @@ end
111
119
 
112
120
  describe Sequel::Model::Associations::AssociationReflection, "#select" do
113
121
  before do
114
- @c = Class.new(Sequel::Model)
122
+ @c = Class.new(Sequel::Model(:foo))
115
123
  class ::ParParent < Sequel::Model; end
116
124
  end
125
+ after do
126
+ Object.send(:remove_const, :ParParent)
127
+ end
117
128
 
118
129
  it "should use the :select value if present" do
119
130
  @c.many_to_one :c, :class=>ParParent, :select=>[:par_parents__id]
@@ -143,9 +154,12 @@ end
143
154
 
144
155
  describe Sequel::Model::Associations::AssociationReflection, "#associated_object_keys" do
145
156
  before do
146
- @c = Class.new(Sequel::Model)
157
+ @c = Class.new(Sequel::Model(:foo))
147
158
  class ::ParParent < Sequel::Model; end
148
159
  end
160
+ after do
161
+ Object.send(:remove_const, :ParParent)
162
+ end
149
163
 
150
164
  it "should use the primary keys for a many_to_one association" do
151
165
  @c.many_to_one :c, :class=>ParParent
@@ -175,7 +189,7 @@ end
175
189
 
176
190
  describe Sequel::Model::Associations::AssociationReflection, "#remove_before_destroy?" do
177
191
  before do
178
- @c = Class.new(Sequel::Model)
192
+ @c = Class.new(Sequel::Model(:foo))
179
193
  end
180
194
 
181
195
  it "should be true for many_to_one and many_to_many associations" do
@@ -283,3 +297,65 @@ describe Sequel::Model::Associations::AssociationReflection, "#eager_limit_strat
283
297
  @c.association_reflection(:c).eager_limit_strategy.should be_nil
284
298
  end
285
299
  end
300
+
301
+ describe Sequel::Model, " association reflection methods" do
302
+ before do
303
+ @c1 = Class.new(Sequel::Model(:nodes)) do
304
+ def self.name; 'Node'; end
305
+ def self.to_s; 'Node'; end
306
+ end
307
+ MODEL_DB.reset
308
+ end
309
+
310
+ it "#all_association_reflections should include all association reflection hashes" do
311
+ @c1.all_association_reflections.should == []
312
+
313
+ @c1.associate :many_to_one, :parent, :class => @c1
314
+ @c1.all_association_reflections.collect{|v| v[:name]}.should == [:parent]
315
+ @c1.all_association_reflections.collect{|v| v[:type]}.should == [:many_to_one]
316
+ @c1.all_association_reflections.collect{|v| v[:class]}.should == [@c1]
317
+
318
+ @c1.associate :one_to_many, :children, :class => @c1
319
+ @c1.all_association_reflections.sort_by{|x|x[:name].to_s}
320
+ @c1.all_association_reflections.sort_by{|x|x[:name].to_s}.collect{|v| v[:name]}.should == [:children, :parent]
321
+ @c1.all_association_reflections.sort_by{|x|x[:name].to_s}.collect{|v| v[:type]}.should == [:one_to_many, :many_to_one]
322
+ @c1.all_association_reflections.sort_by{|x|x[:name].to_s}.collect{|v| v[:class]}.should == [@c1, @c1]
323
+ end
324
+
325
+ it "#association_reflection should return nil for nonexistent association" do
326
+ @c1.association_reflection(:blah).should == nil
327
+ end
328
+
329
+ it "#association_reflection should return association reflection hash if association exists" do
330
+ @c1.associate :many_to_one, :parent, :class => @c1
331
+ @c1.association_reflection(:parent).should be_a_kind_of(Sequel::Model::Associations::AssociationReflection)
332
+ @c1.association_reflection(:parent)[:name].should == :parent
333
+ @c1.association_reflection(:parent)[:type].should == :many_to_one
334
+ @c1.association_reflection(:parent)[:class].should == @c1
335
+
336
+ @c1.associate :one_to_many, :children, :class => @c1
337
+ @c1.association_reflection(:children).should be_a_kind_of(Sequel::Model::Associations::AssociationReflection)
338
+ @c1.association_reflection(:children)[:name].should == :children
339
+ @c1.association_reflection(:children)[:type].should == :one_to_many
340
+ @c1.association_reflection(:children)[:class].should == @c1
341
+ end
342
+
343
+ it "#associations should include all association names" do
344
+ @c1.associations.should == []
345
+ @c1.associate :many_to_one, :parent, :class => @c1
346
+ @c1.associations.should == [:parent]
347
+ @c1.associate :one_to_many, :children, :class => @c1
348
+ @c1.associations.sort_by{|x|x.to_s}.should == [:children, :parent]
349
+ end
350
+
351
+ it "association reflections should be copied upon subclasing" do
352
+ @c1.associate :many_to_one, :parent, :class => @c1
353
+ c = Class.new(@c1)
354
+ @c1.associations.should == [:parent]
355
+ c.associations.should == [:parent]
356
+ c.associate :many_to_one, :parent2, :class => @c1
357
+ @c1.associations.should == [:parent]
358
+ c.associations.sort_by{|x| x.to_s}.should == [:parent, :parent2]
359
+ c.instance_methods.map{|x| x.to_s}.should include('parent')
360
+ end
361
+ end
@@ -2,42 +2,47 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe Sequel::Model, "associate" do
4
4
  it "should use explicit class if given a class, symbol, or string" do
5
- MODEL_DB.reset
6
- klass = Class.new(Sequel::Model(:nodes))
7
- class ::ParParent < Sequel::Model
5
+ begin
6
+ klass = Class.new(Sequel::Model(:nodes))
7
+ class ::ParParent < Sequel::Model; end
8
+
9
+ klass.associate :many_to_one, :par_parent0, :class=>ParParent
10
+ klass.associate :one_to_many, :par_parent1s, :class=>'ParParent'
11
+ klass.associate :many_to_many, :par_parent2s, :class=>:ParParent
12
+
13
+ klass.association_reflection(:"par_parent0").associated_class.should == ParParent
14
+ klass.association_reflection(:"par_parent1s").associated_class.should == ParParent
15
+ klass.association_reflection(:"par_parent2s").associated_class.should == ParParent
16
+ ensure
17
+ Object.send(:remove_const, :ParParent)
8
18
  end
9
-
10
- klass.associate :many_to_one, :par_parent0, :class=>ParParent
11
- klass.associate :one_to_many, :par_parent1s, :class=>'ParParent'
12
- klass.associate :many_to_many, :par_parent2s, :class=>:ParParent
13
-
14
- klass.association_reflection(:"par_parent0").associated_class.should == ParParent
15
- klass.association_reflection(:"par_parent1s").associated_class.should == ParParent
16
- klass.association_reflection(:"par_parent2s").associated_class.should == ParParent
17
19
  end
18
20
 
19
21
  it "should default to associating to other models in the same scope" do
20
- class ::AssociationModuleTest
21
- class Album < Sequel::Model
22
- many_to_one :artist
23
- many_to_many :tags
24
- end
25
- class Artist< Sequel::Model
26
- one_to_many :albums
27
- end
28
- class Tag < Sequel::Model
29
- many_to_many :albums
22
+ begin
23
+ class ::AssociationModuleTest
24
+ class Album < Sequel::Model
25
+ many_to_one :artist
26
+ many_to_many :tags
27
+ end
28
+ class Artist< Sequel::Model
29
+ one_to_many :albums
30
+ end
31
+ class Tag < Sequel::Model
32
+ many_to_many :albums
33
+ end
30
34
  end
35
+
36
+ ::AssociationModuleTest::Album.association_reflection(:artist).associated_class.should == ::AssociationModuleTest::Artist
37
+ ::AssociationModuleTest::Album.association_reflection(:tags).associated_class.should == ::AssociationModuleTest::Tag
38
+ ::AssociationModuleTest::Artist.association_reflection(:albums).associated_class.should == ::AssociationModuleTest::Album
39
+ ::AssociationModuleTest::Tag.association_reflection(:albums).associated_class.should == ::AssociationModuleTest::Album
40
+ ensure
41
+ Object.send(:remove_const, :AssociationModuleTest)
31
42
  end
32
-
33
- ::AssociationModuleTest::Album.association_reflection(:artist).associated_class.should == ::AssociationModuleTest::Artist
34
- ::AssociationModuleTest::Album.association_reflection(:tags).associated_class.should == ::AssociationModuleTest::Tag
35
- ::AssociationModuleTest::Artist.association_reflection(:albums).associated_class.should == ::AssociationModuleTest::Album
36
- ::AssociationModuleTest::Tag.association_reflection(:albums).associated_class.should == ::AssociationModuleTest::Album
37
43
  end
38
44
 
39
45
  it "should add a model_object and association_reflection accessors to the dataset, and return it with the current model object" do
40
- MODEL_DB.reset
41
46
  klass = Class.new(Sequel::Model(:nodes)) do
42
47
  columns :id, :a_id
43
48
  end
@@ -64,7 +69,6 @@ describe Sequel::Model, "associate" do
64
69
  end
65
70
 
66
71
  it "should allow extending the dataset with :extend option" do
67
- MODEL_DB.reset
68
72
  klass = Class.new(Sequel::Model(:nodes)) do
69
73
  columns :id, :a_id
70
74
  end
@@ -91,44 +95,46 @@ describe Sequel::Model, "associate" do
91
95
  end
92
96
 
93
97
  it "should clone an existing association with the :clone option" do
94
- MODEL_DB.reset
95
- klass = Class.new(Sequel::Model(:nodes))
96
-
97
- klass.many_to_one(:par_parent, :order=>:a){1}
98
- klass.one_to_many(:par_parent1s, :class=>'ParParent', :limit=>12){4}
99
- klass.many_to_many(:par_parent2s, :class=>:ParParent, :uniq=>true){2}
98
+ begin
99
+ class ::ParParent < Sequel::Model; end
100
+ klass = Class.new(Sequel::Model(:nodes))
101
+
102
+ klass.many_to_one(:par_parent, :order=>:a){1}
103
+ klass.one_to_many(:par_parent1s, :class=>'ParParent', :limit=>12){4}
104
+ klass.many_to_many(:par_parent2s, :class=>:ParParent, :uniq=>true){2}
100
105
 
101
- klass.many_to_one :par, :clone=>:par_parent, :select=>:b
102
- klass.one_to_many :par1s, :clone=>:par_parent1s, :order=>:b, :limit=>10, :block=>nil
103
- klass.many_to_many(:par2s, :clone=>:par_parent2s, :order=>:c){3}
104
-
105
- klass.association_reflection(:par).associated_class.should == ParParent
106
- klass.association_reflection(:par1s).associated_class.should == ParParent
107
- klass.association_reflection(:par2s).associated_class.should == ParParent
108
-
109
- klass.association_reflection(:par)[:order].should == :a
110
- klass.association_reflection(:par).select.should == :b
111
- klass.association_reflection(:par)[:block].call.should == 1
112
- klass.association_reflection(:par1s)[:limit].should == 10
113
- klass.association_reflection(:par1s)[:order].should == :b
114
- klass.association_reflection(:par1s)[:block].should == nil
115
- klass.association_reflection(:par2s)[:after_load].length.should == 1
116
- klass.association_reflection(:par2s)[:order].should == :c
117
- klass.association_reflection(:par2s)[:block].call.should == 3
106
+ klass.many_to_one :par, :clone=>:par_parent, :select=>:b
107
+ klass.one_to_many :par1s, :clone=>:par_parent1s, :order=>:b, :limit=>10, :block=>nil
108
+ klass.many_to_many(:par2s, :clone=>:par_parent2s, :order=>:c){3}
109
+
110
+ klass.association_reflection(:par).associated_class.should == ParParent
111
+ klass.association_reflection(:par1s).associated_class.should == ParParent
112
+ klass.association_reflection(:par2s).associated_class.should == ParParent
113
+
114
+ klass.association_reflection(:par)[:order].should == :a
115
+ klass.association_reflection(:par).select.should == :b
116
+ klass.association_reflection(:par)[:block].call.should == 1
117
+ klass.association_reflection(:par1s)[:limit].should == 10
118
+ klass.association_reflection(:par1s)[:order].should == :b
119
+ klass.association_reflection(:par1s)[:block].should == nil
120
+ klass.association_reflection(:par2s)[:after_load].length.should == 1
121
+ klass.association_reflection(:par2s)[:order].should == :c
122
+ klass.association_reflection(:par2s)[:block].call.should == 3
123
+ ensure
124
+ Object.send(:remove_const, :ParParent)
125
+ end
118
126
  end
119
127
 
120
128
  end
121
129
 
122
130
  describe Sequel::Model, "many_to_one" do
123
131
  before do
124
- MODEL_DB.reset
125
-
126
132
  @c2 = Class.new(Sequel::Model(:nodes)) do
127
133
  unrestrict_primary_key
128
134
  columns :id, :parent_id, :par_parent_id, :blah
129
135
  end
130
-
131
136
  @dataset = @c2.dataset
137
+ MODEL_DB.reset
132
138
  end
133
139
 
134
140
  it "should use implicit key if omitted" do
@@ -143,31 +149,27 @@ describe Sequel::Model, "many_to_one" do
143
149
  end
144
150
 
145
151
  it "should use implicit class if omitted" do
146
- class ::ParParent < Sequel::Model
152
+ begin
153
+ class ::ParParent < Sequel::Model; end
154
+ @c2.many_to_one :par_parent
155
+ @c2.new(:id => 1, :par_parent_id => 234).par_parent.class.should == ParParent
156
+ MODEL_DB.sqls.should == ["SELECT * FROM par_parents WHERE (par_parents.id = 234) LIMIT 1"]
157
+ ensure
158
+ Object.send(:remove_const, :ParParent)
147
159
  end
148
-
149
- @c2.many_to_one :par_parent
150
-
151
- d = @c2.new(:id => 1, :par_parent_id => 234)
152
- p = d.par_parent
153
- p.class.should == ParParent
154
-
155
- MODEL_DB.sqls.should == ["SELECT * FROM par_parents WHERE (par_parents.id = 234) LIMIT 1"]
156
160
  end
157
161
 
158
162
  it "should use class inside module if given as a string" do
159
- module ::Par
160
- class Parent < Sequel::Model
163
+ begin
164
+ module ::Par
165
+ class Parent < Sequel::Model; end
161
166
  end
167
+ @c2.many_to_one :par_parent, :class=>"Par::Parent"
168
+ @c2.new(:id => 1, :par_parent_id => 234).par_parent.class.should == Par::Parent
169
+ MODEL_DB.sqls.should == ["SELECT * FROM parents WHERE (parents.id = 234) LIMIT 1"]
170
+ ensure
171
+ Object.send(:remove_const, :Par)
162
172
  end
163
-
164
- @c2.many_to_one :par_parent, :class=>"Par::Parent"
165
-
166
- d = @c2.new(:id => 1, :par_parent_id => 234)
167
- p = d.par_parent
168
- p.class.should == Par::Parent
169
-
170
- MODEL_DB.sqls.should == ["SELECT * FROM parents WHERE (parents.id = 234) LIMIT 1"]
171
173
  end
172
174
 
173
175
  it "should use explicit key if given" do
@@ -181,6 +183,12 @@ describe Sequel::Model, "many_to_one" do
181
183
  MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.id = 567) LIMIT 1"]
182
184
  end
183
185
 
186
+ it "should respect :qualify => false option" do
187
+ @c2.many_to_one :parent, :class => @c2, :key => :blah, :qualify=>false
188
+ @c2.new(:id => 1, :blah => 567).parent
189
+ MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (id = 567) LIMIT 1"]
190
+ end
191
+
184
192
  it "should use :primary_key option if given" do
185
193
  @c2.many_to_one :parent, :class => @c2, :key => :blah, :primary_key => :pk
186
194
  @c2.new(:id => 1, :blah => 567).parent
@@ -218,14 +226,12 @@ describe Sequel::Model, "many_to_one" do
218
226
  MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE ((nodes.id = 567) AND (a = 32)) LIMIT 1"]
219
227
 
220
228
  @c2.many_to_one :parent, :class => @c2, :key => :blah, :conditions=>:a
221
- MODEL_DB.sqls.clear
222
229
  @c2.new(:id => 1, :blah => 567).parent
223
230
  MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE ((nodes.id = 567) AND a) LIMIT 1"]
224
231
  end
225
232
 
226
233
  it "should support :order, :limit (only for offset), and :dataset options, as well as a block" do
227
- c2 = @c2
228
- @c2.many_to_one :child_20, :class => @c2, :key=>:id, :dataset=>proc{c2.filter(:parent_id=>pk)}, :limit=>[10,20], :order=>:name do |ds|
234
+ @c2.many_to_one :child_20, :class => @c2, :key=>:id, :dataset=>proc{model.filter(:parent_id=>pk)}, :limit=>[10,20], :order=>:name do |ds|
229
235
  ds.filter(:x.sql_number > 1)
230
236
  end
231
237
  @c2.load(:id => 100).child_20
@@ -234,24 +240,19 @@ describe Sequel::Model, "many_to_one" do
234
240
 
235
241
  it "should return nil if key value is nil" do
236
242
  @c2.many_to_one :parent, :class => @c2
237
-
238
- d = @c2.new(:id => 1)
239
- d.parent.should == nil
243
+ @c2.new(:id => 1).parent.should == nil
244
+ MODEL_DB.sqls.should == []
240
245
  end
241
246
 
242
247
  it "should cache negative lookup" do
243
248
  @c2.many_to_one :parent, :class => @c2
244
- ds = @c2.dataset
245
- def ds.fetch_rows(sql, &block)
246
- MODEL_DB.sqls << sql
247
- end
248
-
249
+ @c2.dataset._fetch = []
249
250
  d = @c2.new(:id => 1, :parent_id=>555)
250
251
  MODEL_DB.sqls.should == []
251
252
  d.parent.should == nil
252
253
  MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (nodes.id = 555) LIMIT 1']
253
254
  d.parent.should == nil
254
- MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (nodes.id = 555) LIMIT 1']
255
+ MODEL_DB.sqls.should == []
255
256
  end
256
257
 
257
258
  it "should define a setter method" do
@@ -314,11 +315,9 @@ describe Sequel::Model, "many_to_one" do
314
315
  @c2.many_to_one :parent, :class => @c2
315
316
 
316
317
  d = @c2.load(:id => 1)
317
- MODEL_DB.reset
318
318
  d.parent_id = 234
319
319
  d.associations[:parent].should == nil
320
- ds = @c2.dataset
321
- def ds.fetch_rows(sql, &block); MODEL_DB.sqls << sql; yield({:id=>234}) end
320
+ @c2.dataset._fetch = {:id=>234}
322
321
  e = d.parent
323
322
  MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.id = 234) LIMIT 1"]
324
323
  d.associations[:parent].should == e
@@ -382,10 +381,7 @@ describe Sequel::Model, "many_to_one" do
382
381
  it "should have the setter add to the reciprocal one_to_many cached association list if it exists" do
383
382
  @c2.many_to_one :parent, :class => @c2
384
383
  @c2.one_to_many :children, :class => @c2, :key=>:parent_id
385
- ds = @c2.dataset
386
- def ds.fetch_rows(sql, &block)
387
- MODEL_DB.sqls << sql
388
- end
384
+ @c2.dataset._fetch = []
389
385
 
390
386
  d = @c2.new(:id => 1)
391
387
  e = @c2.new(:id => 2)
@@ -394,14 +390,13 @@ describe Sequel::Model, "many_to_one" do
394
390
  e.children.should_not(include(d))
395
391
  MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (nodes.parent_id = 2)']
396
392
 
397
- MODEL_DB.reset
398
393
  d = @c2.new(:id => 1)
399
394
  e = @c2.new(:id => 2)
400
395
  e.children.should_not(include(d))
401
396
  MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (nodes.parent_id = 2)']
402
397
  d.parent = e
403
398
  e.children.should(include(d))
404
- MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (nodes.parent_id = 2)']
399
+ MODEL_DB.sqls.should == []
405
400
  end
406
401
 
407
402
  it "should have many_to_one setter deal with a one_to_one reciprocal" do
@@ -429,10 +424,7 @@ describe Sequel::Model, "many_to_one" do
429
424
  it "should have the setter remove the object from the previous associated object's reciprocal one_to_many cached association list if it exists" do
430
425
  @c2.many_to_one :parent, :class => @c2
431
426
  @c2.one_to_many :children, :class => @c2, :key=>:parent_id
432
- ds = @c2.dataset
433
- def ds.fetch_rows(sql, &block)
434
- MODEL_DB.sqls << sql
435
- end
427
+ @c2.dataset._fetch = []
436
428
 
437
429
  d = @c2.new(:id => 1)
438
430
  e = @c2.new(:id => 2)
@@ -451,17 +443,9 @@ describe Sequel::Model, "many_to_one" do
451
443
  end
452
444
 
453
445
  it "should get all matching records and only return the first if :key option is set to nil" do
454
- c2 = @c2
455
446
  @c2.one_to_many :children, :class => @c2, :key=>:parent_id
456
- @c2.many_to_one :first_grand_parent, :class => @c2, :key=>nil, :eager_graph=>:children, :dataset=>proc{c2.filter(:children_id=>parent_id)}
457
- ds = @c2.dataset
458
- def ds.columns
459
- [:id, :parent_id, :par_parent_id, :blah]
460
- end
461
- def ds.fetch_rows(sql, &block)
462
- MODEL_DB.sqls << sql
463
- yield({:id=>1, :parent_id=>0, :par_parent_id=>3, :blah=>4, :children_id=>2, :children_parent_id=>1, :children_par_parent_id=>5, :children_blah=>6})
464
- end
447
+ @c2.many_to_one :first_grand_parent, :class => @c2, :key=>nil, :eager_graph=>:children, :dataset=>proc{model.filter(:children_id=>parent_id)}
448
+ @c2.dataset.columns(:id, :parent_id, :par_parent_id, :blah)._fetch = [{:id=>1, :parent_id=>0, :par_parent_id=>3, :blah=>4, :children_id=>2, :children_parent_id=>1, :children_par_parent_id=>5, :children_blah=>6}, {}]
465
449
  p = @c2.new(:parent_id=>2)
466
450
  fgp = p.first_grand_parent
467
451
  MODEL_DB.sqls.should == ["SELECT nodes.id, nodes.parent_id, nodes.par_parent_id, nodes.blah, children.id AS children_id, children.parent_id AS children_parent_id, children.par_parent_id AS children_par_parent_id, children.blah AS children_blah FROM nodes LEFT OUTER JOIN nodes AS children ON (children.parent_id = nodes.id) WHERE (children_id = 2)"]
@@ -522,15 +506,15 @@ describe Sequel::Model, "many_to_one" do
522
506
  h = []
523
507
  @c2.many_to_one :parent, :class => @c2, :before_set=>[proc{|x,y| h << x.pk; h << (y ? -y.pk : :y)}, :blah], :after_set=>proc{h << 3}
524
508
  @c2.class_eval do
525
- class_variable_set(:@@blah, h)
509
+ self::Foo = h
526
510
  def []=(a, v)
527
- a == :parent_id ? (self.class.send(:class_variable_get, :@@blah) << (v ? 4 : 5)) : super
511
+ a == :parent_id ? (model::Foo << (v ? 4 : 5)) : super
528
512
  end
529
513
  def blah(x)
530
- self.class.send(:class_variable_get, :@@blah) << (x ? x.pk : :x)
514
+ model::Foo << (x ? x.pk : :x)
531
515
  end
532
516
  def blahr(x)
533
- self.class.send(:class_variable_get, :@@blah) << 6
517
+ model::Foo << 6
534
518
  end
535
519
  end
536
520
  p = @c2.load(:id=>10)
@@ -546,13 +530,11 @@ describe Sequel::Model, "many_to_one" do
546
530
  h = []
547
531
  @c2.many_to_one :parent, :class => @c2, :after_load=>[proc{|x,y| h << [x.pk, y.pk]}, :al]
548
532
  @c2.class_eval do
549
- class_variable_set(:@@blah, h)
533
+ self::Foo = h
550
534
  def al(v)
551
- self.class.send(:class_variable_get, :@@blah) << v.pk
552
- end
553
- def @dataset.fetch_rows(sql)
554
- yield({:id=>20})
535
+ model::Foo << v.pk
555
536
  end
537
+ dataset._fetch = {:id=>20}
556
538
  end
557
539
  p = @c2.load(:id=>10, :parent_id=>20)
558
540
  parent = p.parent
@@ -561,7 +543,6 @@ describe Sequel::Model, "many_to_one" do
561
543
  end
562
544
 
563
545
  it "should support after_load association callback that changes the cached object" do
564
- h = []
565
546
  @c2.many_to_one :parent, :class => @c2, :after_load=>:al
566
547
  @c2.class_eval do
567
548
  def al(v)
@@ -600,35 +581,32 @@ describe Sequel::Model, "many_to_one" do
600
581
  d = @c2.load(:id=>321)
601
582
  p = @c2.new
602
583
  p.associations[:parent] = d
603
- h = []
604
584
  @c2.many_to_one :parent, :class => @c2, :before_set=>:bs, :after_set=>:as
605
585
  @c2.class_eval do
606
- class_variable_set(:@@blah, h)
586
+ self::Foo = []
607
587
  def []=(a, v)
608
- a == :parent_id ? (self.class.send(:class_variable_get, :@@blah) << 5) : super
588
+ a == :parent_id ? (model::Foo << 5) : super
609
589
  end
610
590
  def bs(x)
611
- self.class.send(:class_variable_get, :@@blah) << x.pk
591
+ model::Foo << x.pk
612
592
  end
613
593
  def as(x)
614
- self.class.send(:class_variable_get, :@@blah) << x.pk * 2
594
+ model::Foo << x.pk * 2
615
595
  end
616
596
  end
617
597
  p.parent = c
618
- h.should == [123, 5, 246]
598
+ @c2::Foo.should == [123, 5, 246]
619
599
  end
620
600
  end
621
601
 
622
602
  describe Sequel::Model, "one_to_one" do
623
603
  before do
624
604
  @c1 = Class.new(Sequel::Model(:attributes)) do
625
- def _refresh(ds); end
626
605
  unrestrict_primary_key
627
606
  columns :id, :node_id, :y
628
607
  end
629
608
 
630
609
  @c2 = Class.new(Sequel::Model(:nodes)) do
631
- def _refresh(ds); end
632
610
  unrestrict_primary_key
633
611
  attr_accessor :xxx
634
612
 
@@ -637,24 +615,8 @@ describe Sequel::Model, "one_to_one" do
637
615
  columns :id, :x, :parent_id, :par_parent_id, :blah, :node_id
638
616
  end
639
617
  @dataset = @c2.dataset
640
-
641
- @c2.dataset.extend(Module.new {
642
- def empty?; false; end
643
- def fetch_rows(sql)
644
- @db << sql
645
- yield Hash.new
646
- end
647
- })
648
-
649
- @c1.dataset.extend(Module.new {
650
- def empty?; opts.has_key?(:empty) ? (super; true) : false; end
651
- def fetch_rows(sql)
652
- @db << sql
653
- yield Hash.new
654
- end
655
- })
656
-
657
- @dataset = @c2.dataset
618
+ @dataset._fetch = {}
619
+ @c1.dataset._fetch = {}
658
620
  MODEL_DB.reset
659
621
  end
660
622
 
@@ -676,26 +638,24 @@ describe Sequel::Model, "one_to_one" do
676
638
  it "should add a setter method" do
677
639
  @c2.one_to_one :attribute, :class => @c1
678
640
  attrib = @c1.new(:id=>3)
679
- d = @c1.dataset
680
- @c1.class_eval{remove_method :_refresh}
681
- def d.fetch_rows(s); yield({:id=>3}) end
641
+ @c1.dataset._fetch = {:id=>3}
682
642
  @c2.new(:id => 1234).attribute = attrib
643
+ sqls = MODEL_DB.sqls
683
644
  ['INSERT INTO attributes (node_id, id) VALUES (1234, 3)',
684
- 'INSERT INTO attributes (id, node_id) VALUES (3, 1234)'].should(include(MODEL_DB.sqls.last))
685
- MODEL_DB.sqls.first.should == 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))'
686
- MODEL_DB.sqls.length.should == 2
645
+ 'INSERT INTO attributes (id, node_id) VALUES (3, 1234)'].should(include(sqls.slice! 1))
646
+ sqls.should == ['UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))', "SELECT * FROM attributes WHERE (id = 3) LIMIT 1"]
647
+
687
648
  @c2.new(:id => 1234).attribute.should == attrib
688
- MODEL_DB.sqls.clear
689
649
  attrib = @c1.load(:id=>3)
690
650
  @c2.new(:id => 1234).attribute = attrib
691
- MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))',
651
+ MODEL_DB.sqls.should == ["SELECT * FROM attributes WHERE (attributes.node_id = 1234) LIMIT 1",
652
+ 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (id != 3))',
692
653
  "UPDATE attributes SET node_id = 1234 WHERE (id = 3)"]
693
654
  end
694
655
 
695
656
  it "should use a transaction in the setter method" do
696
657
  @c2.one_to_one :attribute, :class => @c1
697
658
  @c2.use_transactions = true
698
- MODEL_DB.sqls.clear
699
659
  attrib = @c1.load(:id=>3)
700
660
  @c2.new(:id => 1234).attribute = attrib
701
661
  MODEL_DB.sqls.should == ['BEGIN',
@@ -708,7 +668,6 @@ describe Sequel::Model, "one_to_one" do
708
668
  @c2.one_to_one :attribute, :class => @c1, :conditions=>{:a=>1} do |ds|
709
669
  ds.filter(:b=>2)
710
670
  end
711
- MODEL_DB.sqls.clear
712
671
  attrib = @c1.load(:id=>3)
713
672
  @c2.new(:id => 1234).attribute = attrib
714
673
  MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = NULL WHERE ((node_id = 1234) AND (a = 1) AND (b = 2) AND (id != 3))',
@@ -718,30 +677,30 @@ describe Sequel::Model, "one_to_one" do
718
677
  it "should have the setter method respect the :primary_key option" do
719
678
  @c2.one_to_one :attribute, :class => @c1, :primary_key=>:xxx
720
679
  attrib = @c1.new(:id=>3)
721
- d = @c1.dataset
722
- @c1.class_eval{remove_method :_refresh}
723
- def d.fetch_rows(s); yield({:id=>3}) end
680
+ @c1.dataset._fetch = {:id=>3}
724
681
  @c2.new(:id => 1234, :xxx=>5).attribute = attrib
682
+ sqls = MODEL_DB.sqls
725
683
  ['INSERT INTO attributes (node_id, id) VALUES (5, 3)',
726
- 'INSERT INTO attributes (id, node_id) VALUES (3, 5)'].should(include(MODEL_DB.sqls.last))
727
- MODEL_DB.sqls.first.should == 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 5) AND (id != 3))'
728
- MODEL_DB.sqls.length.should == 2
684
+ 'INSERT INTO attributes (id, node_id) VALUES (3, 5)'].should(include(sqls.slice! 1))
685
+ sqls.should == ['UPDATE attributes SET node_id = NULL WHERE ((node_id = 5) AND (id != 3))', "SELECT * FROM attributes WHERE (id = 3) LIMIT 1"]
686
+
729
687
  @c2.new(:id => 321, :xxx=>5).attribute.should == attrib
730
- MODEL_DB.sqls.clear
731
688
  attrib = @c1.load(:id=>3)
732
689
  @c2.new(:id => 621, :xxx=>5).attribute = attrib
733
- MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = NULL WHERE ((node_id = 5) AND (id != 3))',
690
+ MODEL_DB.sqls.should == ["SELECT * FROM attributes WHERE (attributes.node_id = 5) LIMIT 1",
691
+ 'UPDATE attributes SET node_id = NULL WHERE ((node_id = 5) AND (id != 3))',
734
692
  'UPDATE attributes SET node_id = 5 WHERE (id = 3)']
735
693
  end
736
694
 
737
695
  it "should have the setter method respect composite keys" do
738
696
  @c2.one_to_one :attribute, :class => @c1, :key=>[:node_id, :y], :primary_key=>[:id, :x]
739
697
  attrib = @c1.load(:id=>3, :y=>6)
740
- d = @c1.dataset
741
- def d.fetch_rows(s); yield({:id=>3, :y=>6}) end
698
+ @c1.dataset._fetch = {:id=>3, :y=>6}
742
699
  @c2.load(:id => 1234, :x=>5).attribute = attrib
743
- MODEL_DB.sqls.last.should =~ /UPDATE attributes SET (node_id = 1234|y = 5), (node_id = 1234|y = 5) WHERE \(id = 3\)/
744
- MODEL_DB.sqls.first.should =~ /UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(\(node_id = 1234\) AND \(y = 5\) AND \(id != 3\)\)/
700
+ sqls = MODEL_DB.sqls
701
+ sqls.last.should =~ /UPDATE attributes SET (node_id = 1234|y = 5), (node_id = 1234|y = 5) WHERE \(id = 3\)/
702
+ sqls.first.should =~ /UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(\(node_id = 1234\) AND \(y = 5\) AND \(id != 3\)\)/
703
+ sqls.length.should == 2
745
704
  end
746
705
 
747
706
  it "should use implicit key if omitted" do
@@ -756,31 +715,27 @@ describe Sequel::Model, "one_to_one" do
756
715
  end
757
716
 
758
717
  it "should use implicit class if omitted" do
759
- class ::ParParent < Sequel::Model
718
+ begin
719
+ class ::ParParent < Sequel::Model; end
720
+ @c2.one_to_one :par_parent
721
+ @c2.new(:id => 234).par_parent.class.should == ParParent
722
+ MODEL_DB.sqls.should == ["SELECT * FROM par_parents WHERE (par_parents.node_id = 234) LIMIT 1"]
723
+ ensure
724
+ Object.send(:remove_const, :ParParent)
760
725
  end
761
-
762
- @c2.one_to_one :par_parent
763
-
764
- d = @c2.new(:id => 234)
765
- p = d.par_parent
766
- p.class.should == ParParent
767
-
768
- MODEL_DB.sqls.should == ["SELECT * FROM par_parents WHERE (par_parents.node_id = 234) LIMIT 1"]
769
726
  end
770
727
 
771
728
  it "should use class inside module if given as a string" do
772
- module ::Par
773
- class Parent < Sequel::Model
729
+ begin
730
+ module ::Par
731
+ class Parent < Sequel::Model; end
774
732
  end
733
+ @c2.one_to_one :par_parent, :class=>"Par::Parent"
734
+ @c2.new(:id => 234).par_parent.class.should == Par::Parent
735
+ MODEL_DB.sqls.should == ["SELECT * FROM parents WHERE (parents.node_id = 234) LIMIT 1"]
736
+ ensure
737
+ Object.send(:remove_const, :Par)
775
738
  end
776
-
777
- @c2.one_to_one :par_parent, :class=>"Par::Parent"
778
-
779
- d = @c2.new(:id => 234)
780
- p = d.par_parent
781
- p.class.should == Par::Parent
782
-
783
- MODEL_DB.sqls.should == ["SELECT * FROM parents WHERE (parents.node_id = 234) LIMIT 1"]
784
739
  end
785
740
 
786
741
  it "should use explicit key if given" do
@@ -831,14 +786,12 @@ describe Sequel::Model, "one_to_one" do
831
786
  MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE ((nodes.node_id = 567) AND (a = 32)) LIMIT 1"]
832
787
 
833
788
  @c2.one_to_one :parent, :class => @c2, :conditions=>:a
834
- MODEL_DB.sqls.clear
835
789
  @c2.new(:id => 567).parent
836
790
  MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE ((nodes.node_id = 567) AND a) LIMIT 1"]
837
791
  end
838
792
 
839
793
  it "should support :order, :limit (only for offset), and :dataset options, as well as a block" do
840
- c2 = @c2
841
- @c2.one_to_one :child_20, :class => @c2, :key=>:id, :dataset=>proc{c2.filter(:parent_id=>pk)}, :limit=>[10,20], :order=>:name do |ds|
794
+ @c2.one_to_one :child_20, :class => @c2, :key=>:id, :dataset=>proc{model.filter(:parent_id=>pk)}, :limit=>[10,20], :order=>:name do |ds|
842
795
  ds.filter(:x.sql_number > 1)
843
796
  end
844
797
  @c2.load(:id => 100).child_20
@@ -848,24 +801,19 @@ describe Sequel::Model, "one_to_one" do
848
801
  it "should return nil if primary_key value is nil" do
849
802
  @c2.one_to_one :parent, :class => @c2, :primary_key=>:node_id
850
803
 
851
- d = @c2.new(:id => 1)
852
- d.parent.should == nil
804
+ @c2.new(:id => 1).parent.should be_nil
853
805
  MODEL_DB.sqls.should == []
854
806
  end
855
807
 
856
808
  it "should cache negative lookup" do
857
809
  @c2.one_to_one :parent, :class => @c2
858
- ds = @c2.dataset
859
- def ds.fetch_rows(sql, &block)
860
- MODEL_DB.sqls << sql
861
- end
862
-
810
+ @c2.dataset._fetch = []
863
811
  d = @c2.new(:id => 555)
864
812
  MODEL_DB.sqls.should == []
865
813
  d.parent.should == nil
866
814
  MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (nodes.node_id = 555) LIMIT 1']
867
815
  d.parent.should == nil
868
- MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (nodes.node_id = 555) LIMIT 1']
816
+ MODEL_DB.sqls.should == []
869
817
  end
870
818
 
871
819
  it "should define a setter method" do
@@ -873,28 +821,44 @@ describe Sequel::Model, "one_to_one" do
873
821
 
874
822
  d = @c2.new(:id => 1)
875
823
  f = @c2.new(:id => 3, :node_id=> 4321)
824
+ @c2.dataset._fetch = {:id => 3, :node_id=>1}
876
825
  d.parent = f
877
826
  f.values.should == {:id => 3, :node_id=>1}
878
827
  d.parent.should == f
828
+ sqls = MODEL_DB.sqls
829
+ ["INSERT INTO nodes (node_id, id) VALUES (1, 3)",
830
+ "INSERT INTO nodes (id, node_id) VALUES (3, 1)"].should include(sqls.slice! 1)
831
+ sqls.should == ["UPDATE nodes SET node_id = NULL WHERE ((node_id = 1) AND (id != 3))", "SELECT * FROM nodes WHERE (id = 3) LIMIT 1"]
879
832
 
880
833
  d.parent = nil
881
834
  d.parent.should == nil
835
+ MODEL_DB.sqls.should == ["UPDATE nodes SET node_id = NULL WHERE (node_id = 1)"]
882
836
  end
883
837
 
884
838
  it "should have the setter method respect the :primary_key option" do
885
839
  @c2.one_to_one :parent, :class => @c2, :primary_key=>:blah
886
840
  d = @c2.new(:id => 1, :blah => 3)
887
841
  e = @c2.new(:id => 4321, :node_id=>444)
842
+ @c2.dataset._fetch = {:id => 4321, :node_id => 3}
888
843
  d.parent = e
889
844
  e.values.should == {:id => 4321, :node_id => 3}
845
+ sqls = MODEL_DB.sqls
846
+ ["INSERT INTO nodes (node_id, id) VALUES (3, 4321)",
847
+ "INSERT INTO nodes (id, node_id) VALUES (4321, 3)"].should include(sqls.slice! 1)
848
+ sqls.should == ["UPDATE nodes SET node_id = NULL WHERE ((node_id = 3) AND (id != 4321))", "SELECT * FROM nodes WHERE (id = 4321) LIMIT 1"]
890
849
  end
891
850
 
892
851
  it "should have the setter method respect the :key option" do
893
852
  @c2.one_to_one :parent, :class => @c2, :key=>:blah
894
853
  d = @c2.new(:id => 3)
895
854
  e = @c2.new(:id => 4321, :blah=>444)
855
+ @c2.dataset._fetch = {:id => 4321, :blah => 3}
896
856
  d.parent = e
897
857
  e.values.should == {:id => 4321, :blah => 3}
858
+ sqls = MODEL_DB.sqls
859
+ ["INSERT INTO nodes (blah, id) VALUES (3, 4321)",
860
+ "INSERT INTO nodes (id, blah) VALUES (4321, 3)"].should include(sqls.slice! 1)
861
+ sqls.should == ["UPDATE nodes SET blah = NULL WHERE ((blah = 3) AND (id != 4321))", "SELECT * FROM nodes WHERE (id = 4321) LIMIT 1"]
898
862
  end
899
863
 
900
864
  it "should persist changes to associated object when the setter is called" do
@@ -910,12 +874,11 @@ describe Sequel::Model, "one_to_one" do
910
874
 
911
875
  d = @c2.load(:id => 1)
912
876
  d.associations[:parent].should == nil
913
- ds = @c2.dataset
914
- def ds.fetch_rows(sql, &block); MODEL_DB.sqls << sql; yield({:id=>234}) end
877
+ @c2.dataset._fetch = {:id=>234}
915
878
  e = d.parent
916
879
  MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.node_id = 1) LIMIT 1"]
917
880
  d.parent
918
- MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (nodes.node_id = 1) LIMIT 1"]
881
+ MODEL_DB.sqls.should == []
919
882
  d.associations[:parent].should == e
920
883
  end
921
884
 
@@ -957,7 +920,6 @@ describe Sequel::Model, "one_to_one" do
957
920
  e.child.should == d
958
921
  MODEL_DB.sqls.should == ["UPDATE nodes SET parent_id = NULL WHERE ((parent_id = 1) AND (id != 2))",
959
922
  "UPDATE nodes SET parent_id = 1 WHERE (id = 2)"]
960
- MODEL_DB.reset
961
923
  d.parent = nil
962
924
  e.child.should == nil
963
925
  MODEL_DB.sqls.should == ["UPDATE nodes SET parent_id = NULL WHERE (parent_id = 1)"]
@@ -966,17 +928,13 @@ describe Sequel::Model, "one_to_one" do
966
928
  it "should have the setter remove the object from the previous associated object's reciprocal many_to_one cached association list if it exists" do
967
929
  @c2.one_to_one :parent, :class => @c2, :key=>:parent_id
968
930
  @c2.many_to_one :child, :class => @c2, :key=>:parent_id
969
- ds = @c2.dataset
970
- def ds.fetch_rows(sql, &block)
971
- MODEL_DB.sqls << sql
972
- end
931
+ @c2.dataset._fetch = []
973
932
 
974
933
  d = @c2.load(:id => 1)
975
934
  e = @c2.load(:id => 2)
976
935
  f = @c2.load(:id => 3)
977
936
  e.child.should == nil
978
937
  f.child.should == nil
979
- MODEL_DB.reset
980
938
  d.parent = e
981
939
  e.child.should == d
982
940
  d.parent = f
@@ -1018,12 +976,12 @@ describe Sequel::Model, "one_to_one" do
1018
976
  h = []
1019
977
  @c2.one_to_one :parent, :class => @c2, :before_set=>[proc{|x,y| h << x.pk; h << (y ? -y.pk : :y)}, :blah], :after_set=>proc{h << 3}
1020
978
  @c2.class_eval do
1021
- class_variable_set(:@@blah, h)
979
+ self::Foo = h
1022
980
  def blah(x)
1023
- self.class.send(:class_variable_get, :@@blah) << (x ? x.pk : :x)
981
+ model::Foo << (x ? x.pk : :x)
1024
982
  end
1025
983
  def blahr(x)
1026
- self.class.send(:class_variable_get, :@@blah) << 6
984
+ model::Foo << 6
1027
985
  end
1028
986
  end
1029
987
  p = @c2.load(:id=>10)
@@ -1039,13 +997,11 @@ describe Sequel::Model, "one_to_one" do
1039
997
  h = []
1040
998
  @c2.one_to_one :parent, :class => @c2, :after_load=>[proc{|x,y| h << [x.pk, y.pk]}, :al]
1041
999
  @c2.class_eval do
1042
- class_variable_set(:@@blah, h)
1000
+ self::Foo = h
1043
1001
  def al(v)
1044
- self.class.send(:class_variable_get, :@@blah) << v.pk
1045
- end
1046
- def @dataset.fetch_rows(sql)
1047
- yield({:id=>20})
1002
+ model::Foo << v.pk
1048
1003
  end
1004
+ @dataset._fetch = {:id=>20}
1049
1005
  end
1050
1006
  p = @c2.load(:id=>10)
1051
1007
  parent = p.parent
@@ -1083,15 +1039,15 @@ describe Sequel::Model, "one_to_one" do
1083
1039
  h = []
1084
1040
  @c2.one_to_one :parent, :class => @c2, :before_set=>:bs, :after_set=>:as
1085
1041
  @c2.class_eval do
1086
- class_variable_set(:@@blah, h)
1042
+ self::Foo = h
1087
1043
  def []=(a, v)
1088
- a == :node_id ? (self.class.send(:class_variable_get, :@@blah) << 5) : super
1044
+ a == :node_id ? (model::Foo << 5) : super
1089
1045
  end
1090
1046
  def bs(x)
1091
- self.class.send(:class_variable_get, :@@blah) << x.pk
1047
+ model::Foo << x.pk
1092
1048
  end
1093
1049
  def as(x)
1094
- self.class.send(:class_variable_get, :@@blah) << x.pk * 2
1050
+ model::Foo << x.pk * 2
1095
1051
  end
1096
1052
  end
1097
1053
  p.parent = c
@@ -1107,16 +1063,9 @@ end
1107
1063
 
1108
1064
  describe Sequel::Model, "one_to_many" do
1109
1065
  before do
1110
- MODEL_DB.reset
1111
-
1112
1066
  @c1 = Class.new(Sequel::Model(:attributes)) do
1113
- def _refresh(ds); end
1114
1067
  unrestrict_primary_key
1115
1068
  columns :id, :node_id, :y, :z
1116
-
1117
- def self.[](id)
1118
- load(id.is_a?(Array) ? {:id => id[0], :z => id[1]} : {:id => id})
1119
- end
1120
1069
  end
1121
1070
 
1122
1071
  @c2 = Class.new(Sequel::Model(:nodes)) do
@@ -1129,66 +1078,50 @@ describe Sequel::Model, "one_to_many" do
1129
1078
  columns :id, :x
1130
1079
  end
1131
1080
  @dataset = @c2.dataset
1132
-
1133
- @c2.dataset.extend(Module.new {
1134
- def empty?; false; end
1135
- def fetch_rows(sql)
1136
- @db << sql
1137
- yield Hash.new
1138
- end
1139
- })
1140
-
1141
- @c1.dataset.extend(Module.new {
1142
- def empty?; opts.has_key?(:empty) ? (super; true) : false; end
1143
- def fetch_rows(sql)
1144
- @db << sql
1145
- yield Hash.new
1146
- end
1147
- })
1081
+ @dataset._fetch = {}
1082
+ @c1.dataset._fetch = proc{|sql| sql =~ /SELECT 1/ ? {:a=>1} : {}}
1083
+ MODEL_DB.reset
1148
1084
  end
1149
1085
 
1150
1086
  it "should use implicit key if omitted" do
1151
1087
  @c2.one_to_many :attributes, :class => @c1
1152
-
1153
- n = @c2.new(:id => 1234)
1154
- a = n.attributes_dataset
1155
- a.should be_a_kind_of(Sequel::Dataset)
1156
- a.sql.should == 'SELECT * FROM attributes WHERE (attributes.node_id = 1234)'
1088
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT * FROM attributes WHERE (attributes.node_id = 1234)'
1157
1089
  end
1158
1090
 
1159
1091
  it "should use implicit class if omitted" do
1160
- class ::HistoricalValue < Sequel::Model
1092
+ begin
1093
+ class ::HistoricalValue < Sequel::Model; end
1094
+ @c2.one_to_many :historical_values
1095
+
1096
+ v = @c2.new(:id => 1234).historical_values_dataset
1097
+ v.should be_a_kind_of(Sequel::Dataset)
1098
+ v.sql.should == 'SELECT * FROM historical_values WHERE (historical_values.node_id = 1234)'
1099
+ v.model.should == HistoricalValue
1100
+ ensure
1101
+ Object.send(:remove_const, :HistoricalValue)
1161
1102
  end
1162
-
1163
- @c2.one_to_many :historical_values
1164
-
1165
- n = @c2.new(:id => 1234)
1166
- v = n.historical_values_dataset
1167
- v.should be_a_kind_of(Sequel::Dataset)
1168
- v.sql.should == 'SELECT * FROM historical_values WHERE (historical_values.node_id = 1234)'
1169
- v.model.should == HistoricalValue
1170
1103
  end
1171
1104
 
1172
1105
  it "should use class inside a module if given as a string" do
1173
- module ::Historical
1174
- class Value < Sequel::Model
1106
+ begin
1107
+ module ::Historical
1108
+ class Value < Sequel::Model; end
1175
1109
  end
1110
+ @c2.one_to_many :historical_values, :class=>'Historical::Value'
1111
+
1112
+ v = @c2.new(:id => 1234).historical_values_dataset
1113
+ v.should be_a_kind_of(Sequel::Dataset)
1114
+ v.sql.should == 'SELECT * FROM values WHERE (values.node_id = 1234)'
1115
+ v.model.should == Historical::Value
1116
+ ensure
1117
+ Object.send(:remove_const, :Historical)
1176
1118
  end
1177
-
1178
- @c2.one_to_many :historical_values, :class=>'Historical::Value'
1179
-
1180
- n = @c2.new(:id => 1234)
1181
- v = n.historical_values_dataset
1182
- v.should be_a_kind_of(Sequel::Dataset)
1183
- v.sql.should == 'SELECT * FROM values WHERE (values.node_id = 1234)'
1184
- v.model.should == Historical::Value
1185
1119
  end
1186
1120
 
1187
1121
  it "should use a callback if given one as the argument" do
1188
1122
  @c2.one_to_many :attributes, :class => @c1, :key => :nodeid
1189
1123
 
1190
- d = @c2.create(:id => 1234)
1191
- MODEL_DB.reset
1124
+ d = @c2.load(:id => 1234)
1192
1125
  d.associations[:attributes] = []
1193
1126
  d.attributes(proc{|ds| ds.filter{name > 'M'}}).should_not == []
1194
1127
  MODEL_DB.sqls.should == ["SELECT * FROM attributes WHERE ((attributes.nodeid = 1234) AND (name > 'M'))"]
@@ -1196,11 +1129,7 @@ describe Sequel::Model, "one_to_many" do
1196
1129
 
1197
1130
  it "should use explicit key if given" do
1198
1131
  @c2.one_to_many :attributes, :class => @c1, :key => :nodeid
1199
-
1200
- n = @c2.new(:id => 1234)
1201
- a = n.attributes_dataset
1202
- a.should be_a_kind_of(Sequel::Dataset)
1203
- a.sql.should == 'SELECT * FROM attributes WHERE (attributes.nodeid = 1234)'
1132
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT * FROM attributes WHERE (attributes.nodeid = 1234)'
1204
1133
  end
1205
1134
 
1206
1135
  it "should support_composite keys" do
@@ -1225,10 +1154,8 @@ describe Sequel::Model, "one_to_many" do
1225
1154
  it "should define an add_ method that works on existing records" do
1226
1155
  @c2.one_to_many :attributes, :class => @c1
1227
1156
 
1228
- n = @c2.new(:id => 1234)
1229
- a = @c1.new(:id => 2345)
1230
- a.save
1231
- MODEL_DB.reset
1157
+ n = @c2.load(:id => 1234)
1158
+ a = @c1.load(:id => 2345)
1232
1159
  a.should == n.add_attribute(a)
1233
1160
  a.values.should == {:node_id => 1234, :id => 2345}
1234
1161
  MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = 1234 WHERE (id = 2345)']
@@ -1237,34 +1164,32 @@ describe Sequel::Model, "one_to_many" do
1237
1164
  it "should define an add_ method that works on new records" do
1238
1165
  @c2.one_to_many :attributes, :class => @c1
1239
1166
 
1240
- n = @c2.new(:id => 1234)
1167
+ n = @c2.load(:id => 1234)
1241
1168
  a = @c1.new(:id => 234)
1242
- # do not save
1243
- MODEL_DB.reset
1169
+ @c1.dataset._fetch = {:node_id => 1234, :id => 234}
1244
1170
  a.should == n.add_attribute(a)
1245
- MODEL_DB.sqls.first.should =~ /INSERT INTO attributes \((node_)?id, (node_)?id\) VALUES \(1?234, 1?234\)/
1171
+ sqls = MODEL_DB.sqls
1172
+ sqls.shift.should =~ /INSERT INTO attributes \((node_)?id, (node_)?id\) VALUES \(1?234, 1?234\)/
1173
+ sqls.should == ["SELECT * FROM attributes WHERE (id = 234) LIMIT 1"]
1246
1174
  a.values.should == {:node_id => 1234, :id => 234}
1247
1175
  end
1248
1176
 
1249
1177
  it "should define a remove_ method that works on existing records" do
1250
1178
  @c2.one_to_many :attributes, :class => @c1
1251
1179
 
1252
- n = @c2.new(:id => 1234)
1253
- a = @c1.new(:id => 2345, :node_id => 1234)
1254
- a.save
1255
- MODEL_DB.reset
1180
+ n = @c2.load(:id => 1234)
1181
+ a = @c1.load(:id => 2345, :node_id => 1234)
1256
1182
  a.should == n.remove_attribute(a)
1257
1183
  a.values.should == {:node_id => nil, :id => 2345}
1258
- MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = NULL WHERE (id = 2345)']
1184
+ MODEL_DB.sqls.should == ["SELECT 1 FROM attributes WHERE ((attributes.node_id = 1234) AND (id = 2345)) LIMIT 1", 'UPDATE attributes SET node_id = NULL WHERE (id = 2345)']
1259
1185
  end
1260
1186
 
1261
1187
  it "should have the remove_ method raise an error if the passed object is not already associated" do
1262
1188
  @c2.one_to_many :attributes, :class => @c1
1263
- @c1.dataset.opts[:empty] = true
1264
1189
 
1265
1190
  n = @c2.new(:id => 1234)
1266
1191
  a = @c1.load(:id => 2345, :node_id => 1234)
1267
- MODEL_DB.reset
1192
+ @c1.dataset._fetch = []
1268
1193
  proc{n.remove_attribute(a)}.should raise_error(Sequel::Error)
1269
1194
  MODEL_DB.sqls.should == ["SELECT 1 FROM attributes WHERE ((attributes.node_id = 1234) AND (id = 2345)) LIMIT 1"]
1270
1195
  end
@@ -1273,16 +1198,19 @@ describe Sequel::Model, "one_to_many" do
1273
1198
  @c2.one_to_many :attributes, :class => @c1
1274
1199
  n = @c2.new(:id => 1234)
1275
1200
  MODEL_DB.reset
1276
- @c1.load(:node_id => 1234, :id => 234).should == n.add_attribute(:id => 234)
1277
- MODEL_DB.sqls.first.should =~ /INSERT INTO attributes \((node_)?id, (node_)?id\) VALUES \(1?234, 1?234\)/
1201
+ @c1.dataset._fetch = {:node_id => 1234, :id => 234}
1202
+ n.add_attribute(:id => 234).should == @c1.load(:node_id => 1234, :id => 234)
1203
+ sqls = MODEL_DB.sqls
1204
+ sqls.shift.should =~ /INSERT INTO attributes \((node_)?id, (node_)?id\) VALUES \(1?234, 1?234\)/
1205
+ sqls.should == ["SELECT * FROM attributes WHERE (id = 234) LIMIT 1"]
1278
1206
  end
1279
1207
 
1280
1208
  it "should accept a primary key for the add_ method" do
1281
1209
  @c2.one_to_many :attributes, :class => @c1
1282
1210
  n = @c2.new(:id => 1234)
1283
- MODEL_DB.reset
1284
- @c1.load(:node_id => 1234, :id => 234).should == n.add_attribute(234)
1285
- MODEL_DB.sqls.first.should == "UPDATE attributes SET node_id = 1234 WHERE (id = 234)"
1211
+ @c1.dataset._fetch = {:id=>234, :node_id=>nil}
1212
+ n.add_attribute(234).should == @c1.load(:node_id => 1234, :id => 234)
1213
+ MODEL_DB.sqls.should == ["SELECT * FROM attributes WHERE id = 234", "UPDATE attributes SET node_id = 1234 WHERE (id = 234)"]
1286
1214
  end
1287
1215
 
1288
1216
  it "should raise an error in the add_ method if the passed associated object is not of the correct type" do
@@ -1293,13 +1221,8 @@ describe Sequel::Model, "one_to_many" do
1293
1221
  it "should accept a primary key for the remove_ method and remove an existing record" do
1294
1222
  @c2.one_to_many :attributes, :class => @c1
1295
1223
  n = @c2.new(:id => 1234)
1296
- ds = @c1.dataset
1297
- def ds.fetch_rows(sql)
1298
- db << sql
1299
- yield({:id=>234, :node_id=>1234})
1300
- end
1301
- MODEL_DB.reset
1302
- @c1.load(:node_id => nil, :id => 234).should == n.remove_attribute(234)
1224
+ @c1.dataset._fetch = {:id=>234, :node_id=>1234}
1225
+ n.remove_attribute(234).should == @c1.load(:node_id => nil, :id => 234)
1303
1226
  MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (attributes.id = 234)) LIMIT 1',
1304
1227
  'UPDATE attributes SET node_id = NULL WHERE (id = 234)']
1305
1228
  end
@@ -1313,10 +1236,8 @@ describe Sequel::Model, "one_to_many" do
1313
1236
  @c2.one_to_many :attributes, :class => @c1, :primary_key=>:xxx
1314
1237
 
1315
1238
  n = @c2.new(:id => 1234, :xxx=>5)
1316
- a = @c1.new(:id => 2345)
1317
- a.save
1318
- MODEL_DB.reset
1319
- a.should == n.add_attribute(a)
1239
+ a = @c1.load(:id => 2345)
1240
+ n.add_attribute(a).should == a
1320
1241
  MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = 5 WHERE (id = 2345)']
1321
1242
  end
1322
1243
 
@@ -1324,15 +1245,13 @@ describe Sequel::Model, "one_to_many" do
1324
1245
  @c2.one_to_many :attributes, :class => @c1
1325
1246
 
1326
1247
  n = @c2.new(:id => 1234)
1327
- a = @c1.new(:id => 2345)
1328
- a.save
1329
- MODEL_DB.reset
1248
+ a = @c1.load(:id => 2345)
1330
1249
  n.associations[:attributes] = []
1331
1250
  a.should == n.add_attribute(a)
1332
1251
  a.should == n.add_attribute(a)
1333
1252
  a.values.should == {:node_id => 1234, :id => 2345}
1334
- MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = 1234 WHERE (id = 2345)'] * 2
1335
1253
  n.attributes.should == [a]
1254
+ MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = 1234 WHERE (id = 2345)'] * 2
1336
1255
  end
1337
1256
 
1338
1257
  it "should have add_ method respect composite keys" do
@@ -1340,18 +1259,24 @@ describe Sequel::Model, "one_to_many" do
1340
1259
 
1341
1260
  n = @c2.load(:id => 1234, :x=>5)
1342
1261
  a = @c1.load(:id => 2345)
1343
- a.should == n.add_attribute(a)
1344
- MODEL_DB.sqls.first.should =~ /UPDATE attributes SET (node_id = 1234|y = 5), (node_id = 1234|y = 5) WHERE \(id = 2345\)/
1262
+ n.add_attribute(a).should == a
1263
+ sqls = MODEL_DB.sqls
1264
+ sqls.shift.should =~ /UPDATE attributes SET (node_id = 1234|y = 5), (node_id = 1234|y = 5) WHERE \(id = 2345\)/
1265
+ sqls.should == []
1345
1266
  end
1346
1267
 
1347
1268
  it "should have add_ method accept a composite key" do
1348
1269
  @c1.set_primary_key :id, :z
1349
1270
  @c2.one_to_many :attributes, :class => @c1, :key =>[:node_id, :y], :primary_key=>[:id, :x]
1271
+ @c1.dataset._fetch = {:id => 2345, :z => 8, :node_id => 1234, :y=>5}
1350
1272
 
1351
1273
  n = @c2.load(:id => 1234, :x=>5)
1352
1274
  a = @c1.load(:id => 2345, :z => 8, :node_id => 1234, :y=>5)
1353
- a.should == n.add_attribute([2345, 8])
1354
- MODEL_DB.sqls.first.should =~ /UPDATE attributes SET (node_id|y) = (1234|5), (node_id|y) = (1234|5) WHERE \(\((id|z) = (2345|8)\) AND \((id|z) = (2345|8)\)\)/
1275
+ n.add_attribute([2345, 8]).should == a
1276
+ sqls = MODEL_DB.sqls
1277
+ sqls.shift.should =~ /SELECT \* FROM attributes WHERE \(\((id|z) = (2345|8)\) AND \((id|z) = (2345|8)\)\) LIMIT 1/
1278
+ sqls.shift.should =~ /UPDATE attributes SET (node_id|y) = (1234|5), (node_id|y) = (1234|5) WHERE \(\((id|z) = (2345|8)\) AND \((id|z) = (2345|8)\)\)/
1279
+ sqls.should == []
1355
1280
  end
1356
1281
 
1357
1282
  it "should have remove_ method respect composite keys" do
@@ -1359,24 +1284,22 @@ describe Sequel::Model, "one_to_many" do
1359
1284
 
1360
1285
  n = @c2.load(:id => 1234, :x=>5)
1361
1286
  a = @c1.load(:id => 2345, :node_id=>1234, :y=>5)
1362
- a.should == n.remove_attribute(a)
1363
- MODEL_DB.sqls.first.should =~ /UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(id = 2345\)/
1287
+ n.remove_attribute(a).should == a
1288
+ sqls = MODEL_DB.sqls
1289
+ sqls.pop.should =~ /UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(id = 2345\)/
1290
+ sqls.should == ["SELECT 1 FROM attributes WHERE ((attributes.node_id = 1234) AND (attributes.y = 5) AND (id = 2345)) LIMIT 1"]
1364
1291
  end
1365
1292
 
1366
1293
  it "should accept a array of composite primary key values for the remove_ method and remove an existing record" do
1367
1294
  @c1.set_primary_key :id, :y
1368
1295
  @c2.one_to_many :attributes, :class => @c1, :key=>:node_id, :primary_key=>:id
1369
1296
  n = @c2.new(:id => 123)
1370
- ds = @c1.dataset
1371
- def ds.fetch_rows(sql)
1372
- db << sql
1373
- yield({:id=>234, :node_id=>123, :y=>5})
1374
- end
1375
- MODEL_DB.reset
1376
- @c1.load(:node_id => nil, :y => 5, :id => 234).should == n.remove_attribute([234, 5])
1377
- MODEL_DB.sqls.length.should == 2
1378
- MODEL_DB.sqls.first.should =~ /SELECT \* FROM attributes WHERE \(\(attributes.node_id = 123\) AND \(attributes\.(id|y) = (234|5)\) AND \(attributes\.(id|y) = (234|5)\)\) LIMIT 1/
1379
- MODEL_DB.sqls.last.should =~ /UPDATE attributes SET node_id = NULL WHERE \(\((id|y) = (234|5)\) AND \((id|y) = (234|5)\)\)/
1297
+ @c1.dataset._fetch = {:id=>234, :node_id=>123, :y=>5}
1298
+ n.remove_attribute([234, 5]).should == @c1.load(:node_id => nil, :y => 5, :id => 234)
1299
+ sqls = MODEL_DB.sqls
1300
+ sqls.length.should == 2
1301
+ sqls.first.should =~ /SELECT \* FROM attributes WHERE \(\(attributes.node_id = 123\) AND \(attributes\.(id|y) = (234|5)\) AND \(attributes\.(id|y) = (234|5)\)\) LIMIT 1/
1302
+ sqls.last.should =~ /UPDATE attributes SET node_id = NULL WHERE \(\((id|y) = (234|5)\) AND \((id|y) = (234|5)\)\)/
1380
1303
  end
1381
1304
 
1382
1305
  it "should raise an error in add_ and remove_ if the passed object returns false to save (is not valid)" do
@@ -1409,81 +1332,48 @@ describe Sequel::Model, "one_to_many" do
1409
1332
 
1410
1333
  it "should use :primary_key option if given" do
1411
1334
  @c1.one_to_many :nodes, :class => @c2, :primary_key => :node_id, :key=>:id
1412
- n = @c1.load(:id => 1234, :node_id=>4321)
1413
- n.nodes_dataset.sql.should == "SELECT * FROM nodes WHERE (nodes.id = 4321)"
1335
+ @c1.load(:id => 1234, :node_id=>4321).nodes_dataset.sql.should == "SELECT * FROM nodes WHERE (nodes.id = 4321)"
1414
1336
  end
1415
1337
 
1416
1338
  it "should support a select option" do
1417
1339
  @c2.one_to_many :attributes, :class => @c1, :select => [:id, :name]
1418
-
1419
- n = @c2.new(:id => 1234)
1420
- n.attributes_dataset.sql.should == "SELECT id, name FROM attributes WHERE (attributes.node_id = 1234)"
1340
+ @c2.new(:id => 1234).attributes_dataset.sql.should == "SELECT id, name FROM attributes WHERE (attributes.node_id = 1234)"
1421
1341
  end
1422
1342
 
1423
1343
  it "should support a conditions option" do
1424
1344
  @c2.one_to_many :attributes, :class => @c1, :conditions => {:a=>32}
1425
- n = @c2.new(:id => 1234)
1426
- n.attributes_dataset.sql.should == "SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (a = 32))"
1345
+ @c2.new(:id => 1234).attributes_dataset.sql.should == "SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (a = 32))"
1427
1346
  @c2.one_to_many :attributes, :class => @c1, :conditions => ~:a
1428
- n = @c2.new(:id => 1234)
1429
- n.attributes_dataset.sql.should == "SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND NOT a)"
1347
+ @c2.new(:id => 1234).attributes_dataset.sql.should == "SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND NOT a)"
1430
1348
  end
1431
1349
 
1432
1350
  it "should support an order option" do
1433
1351
  @c2.one_to_many :attributes, :class => @c1, :order => :kind
1434
-
1435
- n = @c2.new(:id => 1234)
1436
- n.attributes_dataset.sql.should == "SELECT * FROM attributes WHERE (attributes.node_id = 1234) ORDER BY kind"
1352
+ @c2.new(:id => 1234).attributes_dataset.sql.should == "SELECT * FROM attributes WHERE (attributes.node_id = 1234) ORDER BY kind"
1437
1353
  end
1438
1354
 
1439
1355
  it "should support an array for the order option" do
1440
1356
  @c2.one_to_many :attributes, :class => @c1, :order => [:kind1, :kind2]
1441
-
1442
- n = @c2.new(:id => 1234)
1443
- n.attributes_dataset.sql.should == "SELECT * FROM attributes WHERE (attributes.node_id = 1234) ORDER BY kind1, kind2"
1357
+ @c2.new(:id => 1234).attributes_dataset.sql.should == "SELECT * FROM attributes WHERE (attributes.node_id = 1234) ORDER BY kind1, kind2"
1444
1358
  end
1445
1359
 
1446
1360
  it "should return array with all members of the association" do
1447
1361
  @c2.one_to_many :attributes, :class => @c1
1448
-
1449
- n = @c2.new(:id => 1234)
1450
- atts = n.attributes
1451
- atts.should be_a_kind_of(Array)
1452
- atts.size.should == 1
1453
- atts.first.should be_a_kind_of(@c1)
1454
- atts.first.values.should == {}
1455
-
1456
- MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (attributes.node_id = 1234)']
1362
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT * FROM attributes WHERE (attributes.node_id = 1234)'
1457
1363
  end
1458
1364
 
1459
1365
  it "should accept a block" do
1460
1366
  @c2.one_to_many :attributes, :class => @c1 do |ds|
1461
1367
  ds.filter(:xxx => @xxx)
1462
1368
  end
1463
-
1464
- n = @c2.new(:id => 1234)
1465
- atts = n.attributes
1466
- atts.should be_a_kind_of(Array)
1467
- atts.size.should == 1
1468
- atts.first.should be_a_kind_of(@c1)
1469
- atts.first.values.should == {}
1470
-
1471
- MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (xxx IS NULL))']
1369
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (xxx IS NULL))'
1472
1370
  end
1473
1371
 
1474
1372
  it "should support :order option with block" do
1475
1373
  @c2.one_to_many :attributes, :class => @c1, :order => :kind do |ds|
1476
1374
  ds.filter(:xxx => @xxx)
1477
1375
  end
1478
-
1479
- n = @c2.new(:id => 1234)
1480
- atts = n.attributes
1481
- atts.should be_a_kind_of(Array)
1482
- atts.size.should == 1
1483
- atts.first.should be_a_kind_of(@c1)
1484
- atts.first.values.should == {}
1485
-
1486
- MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (xxx IS NULL)) ORDER BY kind']
1376
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT * FROM attributes WHERE ((attributes.node_id = 1234) AND (xxx IS NULL)) ORDER BY kind'
1487
1377
  end
1488
1378
 
1489
1379
  it "should have the block argument affect the _dataset method" do
@@ -1495,18 +1385,11 @@ describe Sequel::Model, "one_to_many" do
1495
1385
 
1496
1386
  it "should support a :dataset option that is used instead of the default" do
1497
1387
  c1 = @c1
1498
- @c2.one_to_many :all_other_attributes, :class => @c1, :dataset=>proc{c1.filter(:nodeid=>pk).invert}, :order=>:a, :limit=>10 do |ds|
1388
+ @c2.one_to_many :all_other_attributes, :class => @c1, :dataset=>proc{c1.exclude(:nodeid=>pk)}, :order=>:a, :limit=>10 do |ds|
1499
1389
  ds.filter(:xxx => 5)
1500
1390
  end
1501
-
1502
1391
  @c2.new(:id => 1234).all_other_attributes_dataset.sql.should == 'SELECT * FROM attributes WHERE ((nodeid != 1234) AND (xxx = 5)) ORDER BY a LIMIT 10'
1503
- n = @c2.new(:id => 1234)
1504
- atts = n.all_other_attributes
1505
- atts.should be_a_kind_of(Array)
1506
- atts.size.should == 1
1507
- atts.first.should be_a_kind_of(@c1)
1508
- atts.first.values.should == {}
1509
-
1392
+ @c2.new(:id => 1234).all_other_attributes.should == [@c1.load({})]
1510
1393
  MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE ((nodeid != 1234) AND (xxx = 5)) ORDER BY a LIMIT 10']
1511
1394
  end
1512
1395
 
@@ -1524,9 +1407,7 @@ describe Sequel::Model, "one_to_many" do
1524
1407
 
1525
1408
  it "should set cached instance variable when accessed" do
1526
1409
  @c2.one_to_many :attributes, :class => @c1
1527
-
1528
1410
  n = @c2.new(:id => 1234)
1529
- MODEL_DB.reset
1530
1411
  n.associations.include?(:attributes).should == false
1531
1412
  atts = n.attributes
1532
1413
  atts.should == n.associations[:attributes]
@@ -1535,9 +1416,7 @@ describe Sequel::Model, "one_to_many" do
1535
1416
 
1536
1417
  it "should use cached instance variable if available" do
1537
1418
  @c2.one_to_many :attributes, :class => @c1
1538
-
1539
1419
  n = @c2.new(:id => 1234)
1540
- MODEL_DB.reset
1541
1420
  n.associations[:attributes] = 42
1542
1421
  n.attributes.should == 42
1543
1422
  MODEL_DB.sqls.should == []
@@ -1545,9 +1424,7 @@ describe Sequel::Model, "one_to_many" do
1545
1424
 
1546
1425
  it "should not use cached instance variable if asked to reload" do
1547
1426
  @c2.one_to_many :attributes, :class => @c1
1548
-
1549
1427
  n = @c2.new(:id => 1234)
1550
- MODEL_DB.reset
1551
1428
  n.associations[:attributes] = 42
1552
1429
  n.attributes(true).should_not == 42
1553
1430
  MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (attributes.node_id = 1234)']
@@ -1555,10 +1432,8 @@ describe Sequel::Model, "one_to_many" do
1555
1432
 
1556
1433
  it "should add item to cached instance variable if it exists when calling add_" do
1557
1434
  @c2.one_to_many :attributes, :class => @c1
1558
-
1559
1435
  n = @c2.new(:id => 1234)
1560
- att = @c1.new(:id => 345)
1561
- MODEL_DB.reset
1436
+ att = @c1.load(:id => 345)
1562
1437
  a = []
1563
1438
  n.associations[:attributes] = a
1564
1439
  n.add_attribute(att)
@@ -1580,7 +1455,6 @@ describe Sequel::Model, "one_to_many" do
1580
1455
 
1581
1456
  n = @c2.load(:id => 1234)
1582
1457
  att = @c1.load(:id => 345)
1583
- MODEL_DB.reset
1584
1458
  a = [att]
1585
1459
  n.associations[:attributes] = a
1586
1460
  n.remove_attribute(att)
@@ -1632,13 +1506,9 @@ describe Sequel::Model, "one_to_many" do
1632
1506
  n = @c2.new(:id => 1234)
1633
1507
  atts = n.attributes
1634
1508
  MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (attributes.node_id = 1234)']
1635
- atts.should be_a_kind_of(Array)
1636
- atts.size.should == 1
1637
- atts.first.should be_a_kind_of(@c1)
1638
- atts.first.values.should == {}
1639
- atts.first.node.should == n
1640
-
1641
- MODEL_DB.sqls.length.should == 1
1509
+ atts.should == [@c1.load({})]
1510
+ atts.map{|a| a.node}.should == [n]
1511
+ MODEL_DB.sqls.should == []
1642
1512
  end
1643
1513
 
1644
1514
  it "should use an explicit reciprocal instance variable if given" do
@@ -1647,19 +1517,15 @@ describe Sequel::Model, "one_to_many" do
1647
1517
  n = @c2.new(:id => 1234)
1648
1518
  atts = n.attributes
1649
1519
  MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (attributes.node_id = 1234)']
1650
- atts.should be_a_kind_of(Array)
1651
- atts.size.should == 1
1652
- atts.first.should be_a_kind_of(@c1)
1653
- atts.first.values.should == {}
1654
- atts.first.associations[:wxyz].should == n
1655
-
1656
- MODEL_DB.sqls.length.should == 1
1520
+ atts.should == [@c1.load({})]
1521
+ atts.map{|a| a.associations[:wxyz]}.should == [n]
1522
+ MODEL_DB.sqls.should == []
1657
1523
  end
1658
1524
 
1659
1525
  it "should have an remove_all_ method that removes all associations" do
1660
1526
  @c2.one_to_many :attributes, :class => @c1
1661
1527
  @c2.new(:id => 1234).remove_all_attributes
1662
- MODEL_DB.sqls.first.should == 'UPDATE attributes SET node_id = NULL WHERE (node_id = 1234)'
1528
+ MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = NULL WHERE (node_id = 1234)']
1663
1529
  end
1664
1530
 
1665
1531
  it "should have remove_all method respect association filters" do
@@ -1673,13 +1539,15 @@ describe Sequel::Model, "one_to_many" do
1673
1539
  it "should have the remove_all_ method respect the :primary_key option" do
1674
1540
  @c2.one_to_many :attributes, :class => @c1, :primary_key=>:xxx
1675
1541
  @c2.new(:id => 1234, :xxx=>5).remove_all_attributes
1676
- MODEL_DB.sqls.first.should == 'UPDATE attributes SET node_id = NULL WHERE (node_id = 5)'
1542
+ MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = NULL WHERE (node_id = 5)']
1677
1543
  end
1678
1544
 
1679
1545
  it "should have the remove_all_ method respect composite keys" do
1680
1546
  @c2.one_to_many :attributes, :class => @c1, :key=>[:node_id, :y], :primary_key=>[:id, :x]
1681
1547
  @c2.new(:id => 1234, :x=>5).remove_all_attributes
1682
- MODEL_DB.sqls.first.should =~ /UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(\(node_id = 1234\) AND \(y = 5\)\)/
1548
+ sqls = MODEL_DB.sqls
1549
+ sqls.pop.should =~ /UPDATE attributes SET (node_id|y) = NULL, (node_id|y) = NULL WHERE \(\(node_id = 1234\) AND \(y = 5\)\)/
1550
+ sqls.should == []
1683
1551
  end
1684
1552
 
1685
1553
  it "remove_all should set the cached instance variable to []" do
@@ -1693,10 +1561,8 @@ describe Sequel::Model, "one_to_many" do
1693
1561
  @c2.one_to_many :attributes, :class => @c1
1694
1562
  attrib = @c1.new(:id=>3)
1695
1563
  node = @c2.new(:id => 1234)
1696
- d = @c1.dataset
1697
- def d.fetch_rows(s); end
1564
+ @c1.dataset._fetch = [[], [{:id=>3, :node_id=>1234}]]
1698
1565
  node.attributes.should == []
1699
- def attrib.save(*); self end
1700
1566
  node.add_attribute(attrib)
1701
1567
  node.associations[:attributes].should == [attrib]
1702
1568
  node.remove_all_attributes.should == [attrib]
@@ -1710,15 +1576,12 @@ describe Sequel::Model, "one_to_many" do
1710
1576
  it "remove_all should remove the current item from all reciprocal instance varaibles if it cached instance variable exists" do
1711
1577
  @c2.one_to_many :attributes, :class => @c1
1712
1578
  @c1.many_to_one :node, :class => @c2
1713
- d = @c1.dataset
1714
- def d.fetch_rows(s); end
1715
- d = @c2.dataset
1716
- def d.fetch_rows(s); end
1579
+ @c2.dataset._fetch = []
1580
+ @c1.dataset._fetch = [[], [{:id=>3, :node_id=>1234}]]
1717
1581
  attrib = @c1.new(:id=>3)
1718
- node = @c2.new(:id => 1234)
1582
+ node = @c2.load(:id => 1234)
1719
1583
  node.attributes.should == []
1720
1584
  attrib.node.should == nil
1721
- def attrib.save(*); self end
1722
1585
  node.add_attribute(attrib)
1723
1586
  attrib.associations[:node].should == node
1724
1587
  node.remove_all_attributes
@@ -1806,18 +1669,18 @@ describe Sequel::Model, "one_to_many" do
1806
1669
  h = []
1807
1670
  @c2.one_to_many :attributes, :class => @c1, :before_add=>[proc{|x,y| h << x.pk; h << -y.pk}, :blah], :after_add=>proc{h << 3}, :before_remove=>:blah, :after_remove=>[:blahr]
1808
1671
  @c2.class_eval do
1809
- class_variable_set(:@@blah, h)
1672
+ self::Foo = h
1810
1673
  def _add_attribute(v)
1811
- self.class.send(:class_variable_get, :@@blah) << 4
1674
+ model::Foo << 4
1812
1675
  end
1813
1676
  def _remove_attribute(v)
1814
- self.class.send(:class_variable_get, :@@blah) << 5
1677
+ model::Foo << 5
1815
1678
  end
1816
1679
  def blah(x)
1817
- self.class.send(:class_variable_get, :@@blah) << x.pk
1680
+ model::Foo << x.pk
1818
1681
  end
1819
1682
  def blahr(x)
1820
- self.class.send(:class_variable_get, :@@blah) << 6
1683
+ model::Foo << 6
1821
1684
  end
1822
1685
  end
1823
1686
  p = @c2.load(:id=>10)
@@ -1833,17 +1696,12 @@ describe Sequel::Model, "one_to_many" do
1833
1696
  h = []
1834
1697
  @c2.one_to_many :attributes, :class => @c1, :after_load=>[proc{|x,y| h << [x.pk, y.collect{|z|z.pk}]}, :al]
1835
1698
  @c2.class_eval do
1836
- class_variable_set(:@@blah, h)
1699
+ self::Foo = h
1837
1700
  def al(v)
1838
- v.each{|x| self.class.send(:class_variable_get, :@@blah) << x.pk}
1839
- end
1840
- end
1841
- @c1.class_eval do
1842
- def @dataset.fetch_rows(sql)
1843
- yield({:id=>20})
1844
- yield({:id=>30})
1701
+ v.each{|x| model::Foo << x.pk}
1845
1702
  end
1846
1703
  end
1704
+ @c1.dataset._fetch = [{:id=>20}, {:id=>30}]
1847
1705
  p = @c2.load(:id=>10, :parent_id=>20)
1848
1706
  attributes = p.attributes
1849
1707
  h.should == [[10, [20, 30]], 20, 30]
@@ -1890,23 +1748,13 @@ describe Sequel::Model, "one_to_many" do
1890
1748
  end
1891
1749
 
1892
1750
  describe Sequel::Model, "many_to_many" do
1893
-
1894
1751
  before do
1895
- MODEL_DB.reset
1896
-
1897
1752
  @c1 = Class.new(Sequel::Model(:attributes)) do
1898
1753
  unrestrict_primary_key
1899
1754
  attr_accessor :yyy
1900
1755
  def self.name; 'Attribute'; end
1901
1756
  def self.to_s; 'Attribute'; end
1902
1757
  columns :id, :y
1903
- def _refresh(ds)
1904
- self
1905
- end
1906
-
1907
- def self.[](id)
1908
- load(id.is_a?(Array) ? {:id => id[0], :y => id[1]} : {:id => id})
1909
- end
1910
1758
  end
1911
1759
 
1912
1760
  @c2 = Class.new(Sequel::Model(:nodes)) do
@@ -1918,98 +1766,61 @@ describe Sequel::Model, "many_to_many" do
1918
1766
  columns :id, :x
1919
1767
  end
1920
1768
  @dataset = @c2.dataset
1769
+ @c1.dataset.autoid = 1
1921
1770
 
1922
- [@c1, @c2].each do |c|
1923
- c.dataset.extend(Module.new {
1924
- def fetch_rows(sql)
1925
- @db << sql
1926
- yield Hash.new
1927
- end
1928
- })
1929
- end
1771
+ [@c1, @c2].each{|c| c.dataset._fetch = {}}
1772
+ MODEL_DB.reset
1930
1773
  end
1931
1774
 
1932
1775
  it "should use implicit key values and join table if omitted" do
1933
1776
  @c2.many_to_many :attributes, :class => @c1
1934
-
1935
- n = @c2.new(:id => 1234)
1936
- a = n.attributes_dataset
1937
- a.should be_a_kind_of(Sequel::Dataset)
1938
- a.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234))'
1777
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234))'
1939
1778
  end
1940
1779
 
1941
1780
  it "should use implicit class if omitted" do
1942
- class ::Tag < Sequel::Model
1781
+ begin
1782
+ class ::Tag < Sequel::Model; end
1783
+ @c2.many_to_many :tags
1784
+ @c2.new(:id => 1234).tags_dataset.sql.should == 'SELECT tags.* FROM tags INNER JOIN nodes_tags ON ((nodes_tags.tag_id = tags.id) AND (nodes_tags.node_id = 1234))'
1785
+ ensure
1786
+ Object.send(:remove_const, :Tag)
1943
1787
  end
1944
-
1945
- @c2.many_to_many :tags
1946
-
1947
- n = @c2.new(:id => 1234)
1948
- a = n.tags_dataset
1949
- a.should be_a_kind_of(Sequel::Dataset)
1950
- a.sql.should == 'SELECT tags.* FROM tags INNER JOIN nodes_tags ON ((nodes_tags.tag_id = tags.id) AND (nodes_tags.node_id = 1234))'
1951
1788
  end
1952
1789
 
1953
1790
  it "should use class inside module if given as a string" do
1954
- module ::Historical
1955
- class Tag < Sequel::Model
1791
+ begin
1792
+ module ::Historical
1793
+ class Tag < Sequel::Model; end
1956
1794
  end
1795
+ @c2.many_to_many :tags, :class=>'::Historical::Tag'
1796
+ @c2.new(:id => 1234).tags_dataset.sql.should == 'SELECT tags.* FROM tags INNER JOIN nodes_tags ON ((nodes_tags.tag_id = tags.id) AND (nodes_tags.node_id = 1234))'
1797
+ ensure
1798
+ Object.send(:remove_const, :Historical)
1957
1799
  end
1958
-
1959
- @c2.many_to_many :tags, :class=>'::Historical::Tag'
1960
-
1961
- n = @c2.new(:id => 1234)
1962
- a = n.tags_dataset
1963
- a.should be_a_kind_of(Sequel::Dataset)
1964
- a.sql.should == 'SELECT tags.* FROM tags INNER JOIN nodes_tags ON ((nodes_tags.tag_id = tags.id) AND (nodes_tags.node_id = 1234))'
1965
1800
  end
1966
1801
 
1967
1802
  it "should use explicit key values and join table if given" do
1968
1803
  @c2.many_to_many :attributes, :class => @c1, :left_key => :nodeid, :right_key => :attributeid, :join_table => :attribute2node
1969
-
1970
- n = @c2.new(:id => 1234)
1971
- a = n.attributes_dataset
1972
- a.should be_a_kind_of(Sequel::Dataset)
1973
- a.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attribute2node ON ((attribute2node.attributeid = attributes.id) AND (attribute2node.nodeid = 1234))'
1974
- end
1975
-
1976
- it "should handle an aliased join table when eager loading" do
1977
- r = @c2.many_to_many(:attributes, :class => @c1, :join_table => :attribute2node___attributes_nodes)
1978
-
1979
- a = @c2.eager_loading_dataset(r, @c2.dataset, [:id], nil)
1980
- a.sql.should == 'SELECT id, attributes_nodes.node_id AS x_foreign_key_x FROM nodes'
1804
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attribute2node ON ((attribute2node.attributeid = attributes.id) AND (attribute2node.nodeid = 1234))'
1981
1805
  end
1982
1806
 
1983
1807
  it "should support a conditions option" do
1984
1808
  @c2.many_to_many :attributes, :class => @c1, :conditions => {:a=>32}
1985
- n = @c2.new(:id => 1234)
1986
- a = n.attributes_dataset
1987
- a.should be_a_kind_of(Sequel::Dataset)
1988
- a.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) WHERE (a = 32)'
1809
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) WHERE (a = 32)'
1810
+
1989
1811
  @c2.many_to_many :attributes, :class => @c1, :conditions => ['a = ?', 32]
1990
- n = @c2.new(:id => 1234)
1991
- a = n.attributes_dataset
1992
- a.should be_a_kind_of(Sequel::Dataset)
1993
- a.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) WHERE (a = 32)'
1994
- n.attributes.should == [@c1.load({})]
1812
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) WHERE (a = 32)'
1813
+ @c2.new(:id => 1234).attributes.should == [@c1.load({})]
1995
1814
  end
1996
1815
 
1997
1816
  it "should support an order option" do
1998
1817
  @c2.many_to_many :attributes, :class => @c1, :order => :blah
1999
-
2000
- n = @c2.new(:id => 1234)
2001
- a = n.attributes_dataset
2002
- a.should be_a_kind_of(Sequel::Dataset)
2003
- a.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) ORDER BY blah'
1818
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) ORDER BY blah'
2004
1819
  end
2005
1820
 
2006
1821
  it "should support an array for the order option" do
2007
1822
  @c2.many_to_many :attributes, :class => @c1, :order => [:blah1, :blah2]
2008
-
2009
- n = @c2.new(:id => 1234)
2010
- a = n.attributes_dataset
2011
- a.should be_a_kind_of(Sequel::Dataset)
2012
- a.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) ORDER BY blah1, blah2'
1823
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) ORDER BY blah1, blah2'
2013
1824
  end
2014
1825
 
2015
1826
  it "should support :left_primary_key and :right_primary_key options" do
@@ -2044,19 +1855,13 @@ describe Sequel::Model, "many_to_many" do
2044
1855
  it "should support a select option" do
2045
1856
  @c2.many_to_many :attributes, :class => @c1, :select => :blah
2046
1857
 
2047
- n = @c2.new(:id => 1234)
2048
- a = n.attributes_dataset
2049
- a.should be_a_kind_of(Sequel::Dataset)
2050
- a.sql.should == 'SELECT blah FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234))'
1858
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT blah FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234))'
2051
1859
  end
2052
1860
 
2053
1861
  it "should support an array for the select option" do
2054
1862
  @c2.many_to_many :attributes, :class => @c1, :select => [:attributes.*, :attribute_nodes__blah2]
2055
1863
 
2056
- n = @c2.new(:id => 1234)
2057
- a = n.attributes_dataset
2058
- a.should be_a_kind_of(Sequel::Dataset)
2059
- a.sql.should == 'SELECT attributes.*, attribute_nodes.blah2 FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234))'
1864
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.*, attribute_nodes.blah2 FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234))'
2060
1865
  end
2061
1866
 
2062
1867
  it "should accept a block" do
@@ -2066,11 +1871,7 @@ describe Sequel::Model, "many_to_many" do
2066
1871
 
2067
1872
  n = @c2.new(:id => 1234)
2068
1873
  n.xxx = 555
2069
- a = n.attributes
2070
- a.should be_a_kind_of(Array)
2071
- a.size.should == 1
2072
- a.first.should be_a_kind_of(@c1)
2073
- MODEL_DB.sqls.first.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) WHERE (xxx = 555)'
1874
+ n.attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) WHERE (xxx = 555)'
2074
1875
  end
2075
1876
 
2076
1877
  it "should allow the :order option while accepting a block" do
@@ -2080,20 +1881,9 @@ describe Sequel::Model, "many_to_many" do
2080
1881
 
2081
1882
  n = @c2.new(:id => 1234)
2082
1883
  n.xxx = 555
2083
- a = n.attributes
2084
- a.should be_a_kind_of(Array)
2085
- a.size.should == 1
2086
- a.first.should be_a_kind_of(@c1)
2087
- MODEL_DB.sqls.first.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) WHERE (xxx = 555) ORDER BY blah1, blah2'
1884
+ n.attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) WHERE (xxx = 555) ORDER BY blah1, blah2'
2088
1885
  end
2089
1886
 
2090
- it "should have the block argument affect the _dataset method" do
2091
- @c2.many_to_many :attributes, :class => @c1 do |ds|
2092
- ds.filter(:xxx => 456)
2093
- end
2094
- @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) WHERE (xxx = 456)'
2095
- end
2096
-
2097
1887
  it "should support a :dataset option that is used instead of the default" do
2098
1888
  c1 = @c1
2099
1889
  @c2.many_to_many :attributes, :class => @c1, :dataset=>proc{c1.join_table(:natural, :an).filter(:an__nodeid=>pk)}, :order=> :a, :limit=>10, :select=>nil do |ds|
@@ -2103,11 +1893,8 @@ describe Sequel::Model, "many_to_many" do
2103
1893
  n = @c2.new(:id => 1234)
2104
1894
  n.xxx = 555
2105
1895
  n.attributes_dataset.sql.should == 'SELECT * FROM attributes NATURAL JOIN an WHERE ((an.nodeid = 1234) AND (xxx = 555)) ORDER BY a LIMIT 10'
2106
- a = n.attributes
2107
- a.should be_a_kind_of(Array)
2108
- a.size.should == 1
2109
- a.first.should be_a_kind_of(@c1)
2110
- MODEL_DB.sqls.first.should == 'SELECT * FROM attributes NATURAL JOIN an WHERE ((an.nodeid = 1234) AND (xxx = 555)) ORDER BY a LIMIT 10'
1896
+ n.attributes.should == [@c1.load({})]
1897
+ MODEL_DB.sqls.should == ['SELECT * FROM attributes NATURAL JOIN an WHERE ((an.nodeid = 1234) AND (xxx = 555)) ORDER BY a LIMIT 10']
2111
1898
  end
2112
1899
 
2113
1900
  it "should support a :limit option" do
@@ -2122,15 +1909,32 @@ describe Sequel::Model, "many_to_many" do
2122
1909
  @c2.new(:id => 1234).attributes_dataset.opts[:eager].should == {:attributes=>nil}
2123
1910
  end
2124
1911
 
1912
+ it "should handle an aliased join table" do
1913
+ @c2.many_to_many :attributes, :class => @c1, :join_table => :attribute2node___attributes_nodes
1914
+ n = @c2.load(:id => 1234)
1915
+ a = @c1.load(:id => 2345)
1916
+ n.attributes_dataset.sql.should == "SELECT attributes.* FROM attributes INNER JOIN attribute2node AS attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234))"
1917
+ a.should == n.add_attribute(a)
1918
+ a.should == n.remove_attribute(a)
1919
+ n.remove_all_attributes
1920
+ sqls = MODEL_DB.sqls
1921
+ ['INSERT INTO attribute2node (node_id, attribute_id) VALUES (1234, 2345)',
1922
+ 'INSERT INTO attribute2node (attribute_id, node_id) VALUES (2345, 1234)'].should(include(sqls.shift))
1923
+ ["DELETE FROM attribute2node WHERE ((node_id = 1234) AND (attribute_id = 2345))",
1924
+ "DELETE FROM attribute2node WHERE ((attribute_id = 2345) AND (node_id = 1234))"].should(include(sqls.shift))
1925
+ sqls.should == ["DELETE FROM attribute2node WHERE (node_id = 1234)"]
1926
+ end
1927
+
2125
1928
  it "should define an add_ method that works on existing records" do
2126
1929
  @c2.many_to_many :attributes, :class => @c1
2127
1930
 
2128
1931
  n = @c2.load(:id => 1234)
2129
1932
  a = @c1.load(:id => 2345)
2130
- a.should == n.add_attribute(a)
1933
+ n.add_attribute(a).should == a
1934
+ sqls = MODEL_DB.sqls
2131
1935
  ['INSERT INTO attributes_nodes (node_id, attribute_id) VALUES (1234, 2345)',
2132
- 'INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (2345, 1234)'
2133
- ].should(include(MODEL_DB.sqls.first))
1936
+ 'INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (2345, 1234)'].should(include(sqls.shift))
1937
+ sqls.should == []
2134
1938
  end
2135
1939
 
2136
1940
  it "should define an add_ method that works with a primary key" do
@@ -2138,21 +1942,25 @@ describe Sequel::Model, "many_to_many" do
2138
1942
 
2139
1943
  n = @c2.load(:id => 1234)
2140
1944
  a = @c1.load(:id => 2345)
2141
- a.should == n.add_attribute(2345)
1945
+ @c1.dataset._fetch = {:id=>2345}
1946
+ n.add_attribute(2345).should == a
1947
+ sqls = MODEL_DB.sqls
2142
1948
  ['INSERT INTO attributes_nodes (node_id, attribute_id) VALUES (1234, 2345)',
2143
- 'INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (2345, 1234)'
2144
- ].should(include(MODEL_DB.sqls.first))
1949
+ 'INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (2345, 1234)'].should(include(sqls.pop))
1950
+ sqls.should == ["SELECT * FROM attributes WHERE id = 2345"]
2145
1951
  end
2146
1952
 
2147
1953
  it "should allow passing a hash to the add_ method which creates a new record" do
2148
1954
  @c2.many_to_many :attributes, :class => @c1
2149
1955
 
2150
1956
  n = @c2.load(:id => 1234)
2151
- @c1.load(:id => 1).should == n.add_attribute(:id => 1)
2152
- MODEL_DB.sqls.first.should == 'INSERT INTO attributes (id) VALUES (1)'
1957
+ @c1.dataset._fetch = {:id=>1}
1958
+ n.add_attribute(:id => 1).should == @c1.load(:id => 1)
1959
+ sqls = MODEL_DB.sqls
2153
1960
  ['INSERT INTO attributes_nodes (node_id, attribute_id) VALUES (1234, 1)',
2154
1961
  'INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (1, 1234)'
2155
- ].should(include(MODEL_DB.sqls.last))
1962
+ ].should(include(sqls.pop))
1963
+ sqls.should == ['INSERT INTO attributes (id) VALUES (1)', "SELECT * FROM attributes WHERE (id = 1) LIMIT 1"]
2156
1964
  end
2157
1965
 
2158
1966
  it "should define a remove_ method that works on existing records" do
@@ -2160,8 +1968,8 @@ describe Sequel::Model, "many_to_many" do
2160
1968
 
2161
1969
  n = @c2.new(:id => 1234)
2162
1970
  a = @c1.new(:id => 2345)
2163
- a.should == n.remove_attribute(a)
2164
- MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 2345))'
1971
+ n.remove_attribute(a).should == a
1972
+ MODEL_DB.sqls.should == ['DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 2345))']
2165
1973
  end
2166
1974
 
2167
1975
  it "should raise an error in the add_ method if the passed associated object is not of the correct type" do
@@ -2172,13 +1980,8 @@ describe Sequel::Model, "many_to_many" do
2172
1980
  it "should accept a primary key for the remove_ method and remove an existing record" do
2173
1981
  @c2.many_to_many :attributes, :class => @c1
2174
1982
  n = @c2.new(:id => 1234)
2175
- ds = @c1.dataset
2176
- def ds.fetch_rows(sql)
2177
- db << sql
2178
- yield({:id=>234})
2179
- end
2180
- MODEL_DB.reset
2181
- @c1.load(:id => 234).should == n.remove_attribute(234)
1983
+ @c1.dataset._fetch = {:id=>234}
1984
+ n.remove_attribute(234).should == @c1.load(:id => 234)
2182
1985
  MODEL_DB.sqls.should == ["SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) WHERE (attributes.id = 234) LIMIT 1",
2183
1986
  "DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 234))"]
2184
1987
  end
@@ -2193,10 +1996,12 @@ describe Sequel::Model, "many_to_many" do
2193
1996
 
2194
1997
  n = @c2.load(:id => 1234).set(:xxx=>5)
2195
1998
  a = @c1.load(:id => 2345).set(:yyy=>8)
2196
- a.should == n.add_attribute(a)
1999
+ n.add_attribute(a).should == a
2000
+ sqls = MODEL_DB.sqls
2197
2001
  ['INSERT INTO attributes_nodes (node_id, attribute_id) VALUES (5, 8)',
2198
2002
  'INSERT INTO attributes_nodes (attribute_id, node_id) VALUES (8, 5)'
2199
- ].should(include(MODEL_DB.sqls.first))
2003
+ ].should(include(sqls.pop))
2004
+ sqls.should == []
2200
2005
  end
2201
2006
 
2202
2007
  it "should have add_ method not add the same object to the cached association array if the object is already in the array" do
@@ -2215,7 +2020,9 @@ describe Sequel::Model, "many_to_many" do
2215
2020
  n = @c2.load(:id => 1234, :x=>5)
2216
2021
  a = @c1.load(:id => 2345, :y=>8)
2217
2022
  a.should == n.add_attribute(a)
2218
- m = /INSERT INTO attributes_nodes \((\w+), (\w+), (\w+), (\w+)\) VALUES \((\d+), (\d+), (\d+), (\d+)\)/.match(MODEL_DB.sqls.first)
2023
+ sqls = MODEL_DB.sqls
2024
+ m = /INSERT INTO attributes_nodes \((\w+), (\w+), (\w+), (\w+)\) VALUES \((\d+), (\d+), (\d+), (\d+)\)/.match(sqls.pop)
2025
+ sqls.should == []
2219
2026
  m.should_not == nil
2220
2027
  map = {'l1'=>1234, 'l2'=>5, 'r1'=>2345, 'r2'=>8}
2221
2028
  %w[l1 l2 r1 r2].each do |x|
@@ -2232,10 +2039,15 @@ describe Sequel::Model, "many_to_many" do
2232
2039
 
2233
2040
  it "should have the add_ method respect composite keys" do
2234
2041
  @c2.many_to_many :attributes, :class => @c1, :left_key=>[:l1, :l2], :right_key=>[:r1, :r2], :left_primary_key=>[:id, :x], :right_primary_key=>[:id, :y]
2042
+ @c1.set_primary_key [:id, :y]
2235
2043
  n = @c2.load(:id => 1234, :x=>5)
2236
2044
  a = @c1.load(:id => 2345, :y=>8)
2237
- a.should == n.add_attribute([2345, 8])
2238
- MODEL_DB.sqls.first.should =~ /INSERT INTO attributes_nodes \([lr][12], [lr][12], [lr][12], [lr][12]\) VALUES \((1234|5|2345|8), (1234|5|2345|8), (1234|5|2345|8), (1234|5|2345|8)\)/
2045
+ @c1.dataset._fetch = {:id => 2345, :y=>8}
2046
+ n.add_attribute([2345, 8]).should == a
2047
+ sqls = MODEL_DB.sqls
2048
+ sqls.shift.should =~ /SELECT \* FROM attributes WHERE \(\((id|y) = (8|2345)\) AND \((id|y) = (8|2345)\)\) LIMIT 1/
2049
+ sqls.pop.should =~ /INSERT INTO attributes_nodes \([lr][12], [lr][12], [lr][12], [lr][12]\) VALUES \((1234|5|2345|8), (1234|5|2345|8), (1234|5|2345|8), (1234|5|2345|8)\)/
2050
+ sqls.should == []
2239
2051
  end
2240
2052
 
2241
2053
  it "should have the remove_ method respect the :left_primary_key and :right_primary_key options" do
@@ -2243,8 +2055,8 @@ describe Sequel::Model, "many_to_many" do
2243
2055
 
2244
2056
  n = @c2.new(:id => 1234, :xxx=>5)
2245
2057
  a = @c1.new(:id => 2345, :yyy=>8)
2246
- a.should == n.remove_attribute(a)
2247
- MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE ((node_id = 5) AND (attribute_id = 8))'
2058
+ n.remove_attribute(a).should == a
2059
+ MODEL_DB.sqls.should == ['DELETE FROM attributes_nodes WHERE ((node_id = 5) AND (attribute_id = 8))']
2248
2060
  end
2249
2061
 
2250
2062
  it "should have the remove_ method respect composite keys" do
@@ -2259,17 +2071,12 @@ describe Sequel::Model, "many_to_many" do
2259
2071
  @c1.set_primary_key [:id, :y]
2260
2072
  @c2.many_to_many :attributes, :class => @c1
2261
2073
  n = @c2.new(:id => 1234)
2262
- ds = @c1.dataset
2263
- def ds.fetch_rows(sql)
2264
- db << sql
2265
- yield({:id=>234, :y=>8})
2266
- end
2267
- MODEL_DB.reset
2074
+ @c1.dataset._fetch = {:id=>234, :y=>8}
2268
2075
  @c1.load(:id => 234, :y=>8).should == n.remove_attribute([234, 8])
2076
+ sqls = MODEL_DB.sqls
2269
2077
  ["SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) WHERE ((attributes.id = 234) AND (attributes.y = 8)) LIMIT 1",
2270
- "SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) WHERE ((attributes.y = 8) AND (attributes.id = 234)) LIMIT 1"].should include(MODEL_DB.sqls.first)
2271
- MODEL_DB.sqls.last.should == "DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 234))"
2272
- MODEL_DB.sqls.length.should == 2
2078
+ "SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)) WHERE ((attributes.y = 8) AND (attributes.id = 234)) LIMIT 1"].should include(sqls.shift)
2079
+ sqls.should == ["DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 234))"]
2273
2080
  end
2274
2081
 
2275
2082
  it "should raise an error if the model object doesn't have a valid primary key" do
@@ -2287,6 +2094,7 @@ describe Sequel::Model, "many_to_many" do
2287
2094
  n = @c1.new
2288
2095
  a = @c2.load(:id=>123)
2289
2096
  n.new?.should == true
2097
+ @c1.dataset._fetch = {:id=>1}
2290
2098
  a.add_attribute(n)
2291
2099
  n.new?.should == false
2292
2100
  end
@@ -2313,6 +2121,7 @@ describe Sequel::Model, "many_to_many" do
2313
2121
  n = @c1.new
2314
2122
  a = @c2.load(:id=>123)
2315
2123
  def n.validate() errors.add(:id, 'foo') end
2124
+ @c1.dataset._fetch = {:id=>1}
2316
2125
  a.add_attribute(n)
2317
2126
  n.new?.should == false
2318
2127
  end
@@ -2327,31 +2136,23 @@ describe Sequel::Model, "many_to_many" do
2327
2136
  it "should provide an array with all members of the association" do
2328
2137
  @c2.many_to_many :attributes, :class => @c1
2329
2138
 
2330
- n = @c2.new(:id => 1234)
2331
- atts = n.attributes
2332
- atts.should be_a_kind_of(Array)
2333
- atts.size.should == 1
2334
- atts.first.should be_a_kind_of(@c1)
2335
-
2336
- MODEL_DB.sqls.first.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234))'
2139
+ @c2.new(:id => 1234).attributes.should == [@c1.load({})]
2140
+ MODEL_DB.sqls.should == ['SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234))']
2337
2141
  end
2338
2142
 
2339
2143
  it "should set cached instance variable when accessed" do
2340
2144
  @c2.many_to_many :attributes, :class => @c1
2341
2145
 
2342
2146
  n = @c2.new(:id => 1234)
2343
- MODEL_DB.reset
2344
2147
  n.associations.include?(:attributes).should == false
2345
2148
  atts = n.attributes
2346
2149
  atts.should == n.associations[:attributes]
2347
- MODEL_DB.sqls.length.should == 1
2348
2150
  end
2349
2151
 
2350
2152
  it "should use cached instance variable if available" do
2351
2153
  @c2.many_to_many :attributes, :class => @c1
2352
2154
 
2353
2155
  n = @c2.new(:id => 1234)
2354
- MODEL_DB.reset
2355
2156
  n.associations[:attributes] = 42
2356
2157
  n.attributes.should == 42
2357
2158
  MODEL_DB.sqls.should == []
@@ -2361,18 +2162,16 @@ describe Sequel::Model, "many_to_many" do
2361
2162
  @c2.many_to_many :attributes, :class => @c1
2362
2163
 
2363
2164
  n = @c2.new(:id => 1234)
2364
- MODEL_DB.reset
2365
2165
  n.associations[:attributes] = 42
2366
2166
  n.attributes(true).should_not == 42
2367
- MODEL_DB.sqls.length.should == 1
2167
+ MODEL_DB.sqls.should == ["SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234))"]
2368
2168
  end
2369
2169
 
2370
2170
  it "should add item to cached instance variable if it exists when calling add_" do
2371
2171
  @c2.many_to_many :attributes, :class => @c1
2372
2172
 
2373
2173
  n = @c2.new(:id => 1234)
2374
- att = @c1.new(:id => 345)
2375
- MODEL_DB.reset
2174
+ att = @c1.load(:id => 345)
2376
2175
  a = []
2377
2176
  n.associations[:attributes] = a
2378
2177
  n.add_attribute(att)
@@ -2384,7 +2183,7 @@ describe Sequel::Model, "many_to_many" do
2384
2183
  @c1.many_to_many :nodes, :class => @c2
2385
2184
 
2386
2185
  n = @c2.new(:id => 1234)
2387
- att = @c1.new(:id => 345)
2186
+ att = @c1.load(:id => 345)
2388
2187
  att.associations[:nodes] = []
2389
2188
  n.add_attribute(att)
2390
2189
  att.nodes.should == [n]
@@ -2394,8 +2193,7 @@ describe Sequel::Model, "many_to_many" do
2394
2193
  @c2.many_to_many :attributes, :class => @c1
2395
2194
 
2396
2195
  n = @c2.new(:id => 1234)
2397
- att = @c1.new(:id => 345)
2398
- MODEL_DB.reset
2196
+ att = @c1.load(:id => 345)
2399
2197
  a = [att]
2400
2198
  n.associations[:attributes] = a
2401
2199
  n.remove_attribute(att)
@@ -2442,13 +2240,13 @@ describe Sequel::Model, "many_to_many" do
2442
2240
  it "should have an remove_all_ method that removes all associations" do
2443
2241
  @c2.many_to_many :attributes, :class => @c1
2444
2242
  @c2.new(:id => 1234).remove_all_attributes
2445
- MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE (node_id = 1234)'
2243
+ MODEL_DB.sqls.should == ['DELETE FROM attributes_nodes WHERE (node_id = 1234)']
2446
2244
  end
2447
2245
 
2448
2246
  it "should have the remove_all_ method respect the :left_primary_key option" do
2449
2247
  @c2.many_to_many :attributes, :class => @c1, :left_primary_key=>:xxx
2450
2248
  @c2.new(:id => 1234, :xxx=>5).remove_all_attributes
2451
- MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE (node_id = 5)'
2249
+ MODEL_DB.sqls.should == ['DELETE FROM attributes_nodes WHERE (node_id = 5)']
2452
2250
  end
2453
2251
 
2454
2252
  it "should have the remove_all_ method respect composite keys" do
@@ -2466,10 +2264,9 @@ describe Sequel::Model, "many_to_many" do
2466
2264
 
2467
2265
  it "remove_all should return the array of previously associated items if the cached instance variable exists" do
2468
2266
  @c2.many_to_many :attributes, :class => @c1
2469
- attrib = @c1.new(:id=>3)
2470
- node = @c2.new(:id => 1234)
2471
- d = @c1.dataset
2472
- def d.fetch_rows(s); end
2267
+ attrib = @c1.load(:id=>3)
2268
+ node = @c2.load(:id => 1234)
2269
+ @c1.dataset._fetch = []
2473
2270
  node.attributes.should == []
2474
2271
  node.add_attribute(attrib)
2475
2272
  node.associations[:attributes].should == [attrib]
@@ -2484,11 +2281,9 @@ describe Sequel::Model, "many_to_many" do
2484
2281
  it "remove_all should remove the current item from all reciprocal instance varaibles if it cached instance variable exists" do
2485
2282
  @c2.many_to_many :attributes, :class => @c1
2486
2283
  @c1.many_to_many :nodes, :class => @c2
2487
- d = @c1.dataset
2488
- def d.fetch_rows(s); end
2489
- d = @c2.dataset
2490
- def d.fetch_rows(s); end
2491
- attrib = @c1.new(:id=>3)
2284
+ @c1.dataset._fetch = []
2285
+ @c2.dataset._fetch = []
2286
+ attrib = @c1.load(:id=>3)
2492
2287
  node = @c2.new(:id => 1234)
2493
2288
  node.attributes.should == []
2494
2289
  attrib.nodes.should == []
@@ -2504,8 +2299,9 @@ describe Sequel::Model, "many_to_many" do
2504
2299
  o.add_attribute(@c1.load(:id=>44))
2505
2300
  o.remove_attribute(@c1.load(:id=>45))
2506
2301
  o.remove_all_attributes
2507
- MODEL_DB.sqls.first =~ /INSERT INTO attributes_nodes \((node_id|attribute_id|x), (node_id|attribute_id|x), (node_id|attribute_id|x)\) VALUES \((1234|123|44), (1234|123|44), (1234|123|44)\)/
2508
- MODEL_DB.sqls[1..-1].should == ["DELETE FROM attributes_nodes WHERE ((x = 123) AND (node_id = 1234) AND (attribute_id = 45))",
2302
+ sqls = MODEL_DB.sqls
2303
+ sqls.shift =~ /INSERT INTO attributes_nodes \((node_id|attribute_id|x), (node_id|attribute_id|x), (node_id|attribute_id|x)\) VALUES \((1234|123|44), (1234|123|44), (1234|123|44)\)/
2304
+ sqls.should == ["DELETE FROM attributes_nodes WHERE ((x = 123) AND (node_id = 1234) AND (attribute_id = 45))",
2509
2305
  "DELETE FROM attributes_nodes WHERE ((x = 123) AND (node_id = 1234))"]
2510
2306
  end
2511
2307
 
@@ -2588,18 +2384,18 @@ describe Sequel::Model, "many_to_many" do
2588
2384
  h = []
2589
2385
  @c2.many_to_many :attributes, :class => @c1, :before_add=>[proc{|x,y| h << x.pk; h << -y.pk}, :blah], :after_add=>proc{h << 3}, :before_remove=>:blah, :after_remove=>[:blahr]
2590
2386
  @c2.class_eval do
2591
- class_variable_set(:@@blah, h)
2387
+ self::Foo = h
2592
2388
  def _add_attribute(v)
2593
- self.class.send(:class_variable_get, :@@blah) << 4
2389
+ model::Foo << 4
2594
2390
  end
2595
2391
  def _remove_attribute(v)
2596
- self.class.send(:class_variable_get, :@@blah) << 5
2392
+ model::Foo << 5
2597
2393
  end
2598
2394
  def blah(x)
2599
- self.class.send(:class_variable_get, :@@blah) << x.pk
2395
+ model::Foo << x.pk
2600
2396
  end
2601
2397
  def blahr(x)
2602
- self.class.send(:class_variable_get, :@@blah) << 6
2398
+ model::Foo << 6
2603
2399
  end
2604
2400
  end
2605
2401
  p = @c2.load(:id=>10)
@@ -2615,17 +2411,12 @@ describe Sequel::Model, "many_to_many" do
2615
2411
  h = []
2616
2412
  @c2.many_to_many :attributes, :class => @c1, :after_load=>[proc{|x,y| h << [x.pk, y.collect{|z|z.pk}]}, :al]
2617
2413
  @c2.class_eval do
2618
- class_variable_set(:@@blah, h)
2414
+ self::Foo = h
2619
2415
  def al(v)
2620
- v.each{|x| self.class.send(:class_variable_get, :@@blah) << x.pk}
2621
- end
2622
- end
2623
- @c1.class_eval do
2624
- def @dataset.fetch_rows(sql)
2625
- yield({:id=>20})
2626
- yield({:id=>30})
2416
+ v.each{|x| model::Foo << x.pk}
2627
2417
  end
2628
2418
  end
2419
+ @c1.dataset._fetch = [{:id=>20}, {:id=>30}]
2629
2420
  p = @c2.load(:id=>10, :parent_id=>20)
2630
2421
  attributes = p.attributes
2631
2422
  h.should == [[10, [20, 30]], 20, 30]
@@ -2668,14 +2459,7 @@ describe Sequel::Model, "many_to_many" do
2668
2459
 
2669
2460
  it "should support a :uniq option that removes duplicates from the association" do
2670
2461
  @c2.many_to_many :attributes, :class => @c1, :uniq=>true
2671
- @c1.class_eval do
2672
- def @dataset.fetch_rows(sql)
2673
- yield({:id=>20})
2674
- yield({:id=>30})
2675
- yield({:id=>20})
2676
- yield({:id=>30})
2677
- end
2678
- end
2462
+ @c1.dataset._fetch = [{:id=>20}, {:id=>30}, {:id=>20}, {:id=>30}]
2679
2463
  @c2.load(:id=>10, :parent_id=>20).attributes.should == [@c1.load(:id=>20), @c1.load(:id=>30)]
2680
2464
  end
2681
2465
 
@@ -2696,80 +2480,13 @@ describe Sequel::Model, "many_to_many" do
2696
2480
  @c2.many_to_many :attributes, :class => @c1 do |ds|
2697
2481
  ds.filter(:join_table_att=>3)
2698
2482
  end
2699
- @c1.dataset.instance_eval do
2700
- def fetch_rows(sql, &block)
2701
- db.sqls << sql
2702
- yield(:id=>2)
2703
- end
2704
- end
2483
+ @c1.dataset._fetch = {:id=>2}
2705
2484
  @c2.load(:id=>1).remove_attribute(2)
2706
2485
  MODEL_DB.sqls.should == ["SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1)) WHERE ((join_table_att = 3) AND (attributes.id = 2)) LIMIT 1",
2707
2486
  "DELETE FROM attributes_nodes WHERE ((node_id = 1) AND (attribute_id = 2))"]
2708
2487
  end
2709
2488
  end
2710
2489
 
2711
- describe Sequel::Model, " association reflection methods" do
2712
- before do
2713
- MODEL_DB.reset
2714
- @c1 = Class.new(Sequel::Model(:nodes)) do
2715
- def self.name; 'Node'; end
2716
- def self.to_s; 'Node'; end
2717
- end
2718
- end
2719
-
2720
- it "#all_association_reflections should include all association reflection hashes" do
2721
- @c1.all_association_reflections.should == []
2722
-
2723
- @c1.associate :many_to_one, :parent, :class => @c1
2724
- @c1.all_association_reflections.collect{|v| v[:name]}.should == [:parent]
2725
- @c1.all_association_reflections.collect{|v| v[:type]}.should == [:many_to_one]
2726
- @c1.all_association_reflections.collect{|v| v[:class]}.should == [@c1]
2727
-
2728
- @c1.associate :one_to_many, :children, :class => @c1
2729
- @c1.all_association_reflections.sort_by{|x|x[:name].to_s}
2730
- @c1.all_association_reflections.sort_by{|x|x[:name].to_s}.collect{|v| v[:name]}.should == [:children, :parent]
2731
- @c1.all_association_reflections.sort_by{|x|x[:name].to_s}.collect{|v| v[:type]}.should == [:one_to_many, :many_to_one]
2732
- @c1.all_association_reflections.sort_by{|x|x[:name].to_s}.collect{|v| v[:class]}.should == [@c1, @c1]
2733
- end
2734
-
2735
- it "#association_reflection should return nil for nonexistent association" do
2736
- @c1.association_reflection(:blah).should == nil
2737
- end
2738
-
2739
- it "#association_reflection should return association reflection hash if association exists" do
2740
- @c1.associate :many_to_one, :parent, :class => @c1
2741
- @c1.association_reflection(:parent).should be_a_kind_of(Sequel::Model::Associations::AssociationReflection)
2742
- @c1.association_reflection(:parent)[:name].should == :parent
2743
- @c1.association_reflection(:parent)[:type].should == :many_to_one
2744
- @c1.association_reflection(:parent)[:class].should == @c1
2745
-
2746
- @c1.associate :one_to_many, :children, :class => @c1
2747
- @c1.association_reflection(:children).should be_a_kind_of(Sequel::Model::Associations::AssociationReflection)
2748
- @c1.association_reflection(:children)[:name].should == :children
2749
- @c1.association_reflection(:children)[:type].should == :one_to_many
2750
- @c1.association_reflection(:children)[:class].should == @c1
2751
- end
2752
-
2753
- it "#associations should include all association names" do
2754
- @c1.associations.should == []
2755
- @c1.associate :many_to_one, :parent, :class => @c1
2756
- @c1.associations.should == [:parent]
2757
- @c1.associate :one_to_many, :children, :class => @c1
2758
- @c1.associations.sort_by{|x|x.to_s}.should == [:children, :parent]
2759
- end
2760
-
2761
- it "association reflections should be copied upon subclasing" do
2762
- @c1.associate :many_to_one, :parent, :class => @c1
2763
- c = Class.new(@c1)
2764
- @c1.associations.should == [:parent]
2765
- c.associations.should == [:parent]
2766
- c.associate :many_to_one, :parent2, :class => @c1
2767
- @c1.associations.should == [:parent]
2768
- c.associations.sort_by{|x| x.to_s}.should == [:parent, :parent2]
2769
- c.instance_methods.map{|x| x.to_s}.should include('parent')
2770
- end
2771
- end
2772
-
2773
2490
  describe "Filtering by associations" do
2774
2491
  before do
2775
2492
  @Album = Class.new(Sequel::Model(:albums))