sequel 3.28.0 → 3.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. data/CHANGELOG +119 -3
  2. data/Rakefile +5 -3
  3. data/bin/sequel +1 -5
  4. data/doc/model_hooks.rdoc +9 -1
  5. data/doc/opening_databases.rdoc +49 -40
  6. data/doc/prepared_statements.rdoc +27 -6
  7. data/doc/release_notes/3.28.0.txt +2 -2
  8. data/doc/release_notes/3.29.0.txt +459 -0
  9. data/doc/sharding.rdoc +7 -1
  10. data/doc/testing.rdoc +18 -9
  11. data/doc/transactions.rdoc +41 -1
  12. data/lib/sequel/adapters/ado.rb +28 -17
  13. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  14. data/lib/sequel/adapters/amalgalite.rb +11 -7
  15. data/lib/sequel/adapters/db2.rb +122 -70
  16. data/lib/sequel/adapters/dbi.rb +15 -15
  17. data/lib/sequel/adapters/do.rb +5 -36
  18. data/lib/sequel/adapters/do/mysql.rb +0 -5
  19. data/lib/sequel/adapters/do/postgres.rb +0 -5
  20. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  21. data/lib/sequel/adapters/firebird.rb +3 -6
  22. data/lib/sequel/adapters/ibmdb.rb +24 -16
  23. data/lib/sequel/adapters/informix.rb +2 -4
  24. data/lib/sequel/adapters/jdbc.rb +47 -11
  25. data/lib/sequel/adapters/jdbc/as400.rb +5 -24
  26. data/lib/sequel/adapters/jdbc/db2.rb +0 -5
  27. data/lib/sequel/adapters/jdbc/derby.rb +217 -0
  28. data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
  29. data/lib/sequel/adapters/jdbc/h2.rb +10 -12
  30. data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
  31. data/lib/sequel/adapters/jdbc/informix.rb +0 -5
  32. data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
  33. data/lib/sequel/adapters/jdbc/mysql.rb +0 -10
  34. data/lib/sequel/adapters/jdbc/oracle.rb +70 -3
  35. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -11
  36. data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
  38. data/lib/sequel/adapters/jdbc/transactions.rb +56 -7
  39. data/lib/sequel/adapters/mock.rb +315 -0
  40. data/lib/sequel/adapters/mysql.rb +64 -51
  41. data/lib/sequel/adapters/mysql2.rb +15 -9
  42. data/lib/sequel/adapters/odbc.rb +13 -6
  43. data/lib/sequel/adapters/odbc/db2.rb +0 -4
  44. data/lib/sequel/adapters/odbc/mssql.rb +0 -5
  45. data/lib/sequel/adapters/openbase.rb +2 -4
  46. data/lib/sequel/adapters/oracle.rb +333 -51
  47. data/lib/sequel/adapters/postgres.rb +80 -27
  48. data/lib/sequel/adapters/shared/access.rb +0 -6
  49. data/lib/sequel/adapters/shared/db2.rb +13 -15
  50. data/lib/sequel/adapters/shared/firebird.rb +6 -6
  51. data/lib/sequel/adapters/shared/mssql.rb +23 -18
  52. data/lib/sequel/adapters/shared/mysql.rb +6 -6
  53. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
  54. data/lib/sequel/adapters/shared/oracle.rb +185 -30
  55. data/lib/sequel/adapters/shared/postgres.rb +35 -18
  56. data/lib/sequel/adapters/shared/progress.rb +0 -6
  57. data/lib/sequel/adapters/shared/sqlite.rb +116 -37
  58. data/lib/sequel/adapters/sqlite.rb +16 -8
  59. data/lib/sequel/adapters/swift.rb +5 -5
  60. data/lib/sequel/adapters/swift/mysql.rb +0 -5
  61. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  62. data/lib/sequel/adapters/swift/sqlite.rb +6 -4
  63. data/lib/sequel/adapters/tinytds.rb +13 -10
  64. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -0
  65. data/lib/sequel/core.rb +40 -0
  66. data/lib/sequel/database/connecting.rb +1 -2
  67. data/lib/sequel/database/dataset.rb +3 -3
  68. data/lib/sequel/database/dataset_defaults.rb +58 -0
  69. data/lib/sequel/database/misc.rb +62 -2
  70. data/lib/sequel/database/query.rb +113 -49
  71. data/lib/sequel/database/schema_methods.rb +7 -2
  72. data/lib/sequel/dataset/actions.rb +37 -19
  73. data/lib/sequel/dataset/features.rb +24 -0
  74. data/lib/sequel/dataset/graph.rb +7 -6
  75. data/lib/sequel/dataset/misc.rb +11 -3
  76. data/lib/sequel/dataset/mutation.rb +2 -3
  77. data/lib/sequel/dataset/prepared_statements.rb +6 -4
  78. data/lib/sequel/dataset/query.rb +46 -15
  79. data/lib/sequel/dataset/sql.rb +28 -4
  80. data/lib/sequel/extensions/named_timezones.rb +5 -0
  81. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  82. data/lib/sequel/model.rb +2 -1
  83. data/lib/sequel/model/associations.rb +115 -33
  84. data/lib/sequel/model/base.rb +91 -31
  85. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  86. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  87. data/lib/sequel/plugins/force_encoding.rb +6 -6
  88. data/lib/sequel/plugins/identity_map.rb +1 -1
  89. data/lib/sequel/plugins/many_through_many.rb +6 -10
  90. data/lib/sequel/plugins/prepared_statements.rb +12 -1
  91. data/lib/sequel/plugins/prepared_statements_associations.rb +1 -1
  92. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  93. data/lib/sequel/plugins/serialization.rb +6 -1
  94. data/lib/sequel/plugins/sharding.rb +0 -5
  95. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  96. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  97. data/lib/sequel/plugins/update_primary_key.rb +1 -1
  98. data/lib/sequel/timezones.rb +42 -42
  99. data/lib/sequel/version.rb +1 -1
  100. data/spec/adapters/mssql_spec.rb +29 -29
  101. data/spec/adapters/mysql_spec.rb +86 -104
  102. data/spec/adapters/oracle_spec.rb +48 -76
  103. data/spec/adapters/postgres_spec.rb +98 -33
  104. data/spec/adapters/spec_helper.rb +0 -5
  105. data/spec/adapters/sqlite_spec.rb +24 -21
  106. data/spec/core/connection_pool_spec.rb +9 -15
  107. data/spec/core/core_sql_spec.rb +20 -31
  108. data/spec/core/database_spec.rb +491 -227
  109. data/spec/core/dataset_spec.rb +638 -1051
  110. data/spec/core/expression_filters_spec.rb +0 -1
  111. data/spec/core/mock_adapter_spec.rb +378 -0
  112. data/spec/core/object_graph_spec.rb +48 -114
  113. data/spec/core/schema_generator_spec.rb +3 -3
  114. data/spec/core/schema_spec.rb +51 -114
  115. data/spec/core/spec_helper.rb +3 -90
  116. data/spec/extensions/class_table_inheritance_spec.rb +1 -1
  117. data/spec/extensions/dataset_associations_spec.rb +199 -0
  118. data/spec/extensions/instance_hooks_spec.rb +71 -0
  119. data/spec/extensions/named_timezones_spec.rb +22 -2
  120. data/spec/extensions/nested_attributes_spec.rb +3 -0
  121. data/spec/extensions/schema_spec.rb +1 -1
  122. data/spec/extensions/serialization_modification_detection_spec.rb +1 -0
  123. data/spec/extensions/serialization_spec.rb +5 -8
  124. data/spec/extensions/spec_helper.rb +4 -0
  125. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  126. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  127. data/spec/integration/associations_test.rb +123 -12
  128. data/spec/integration/dataset_test.rb +140 -47
  129. data/spec/integration/eager_loader_test.rb +19 -21
  130. data/spec/integration/model_test.rb +80 -1
  131. data/spec/integration/plugin_test.rb +179 -128
  132. data/spec/integration/prepared_statement_test.rb +92 -91
  133. data/spec/integration/schema_test.rb +42 -23
  134. data/spec/integration/spec_helper.rb +25 -31
  135. data/spec/integration/timezone_test.rb +38 -12
  136. data/spec/integration/transaction_test.rb +161 -34
  137. data/spec/integration/type_test.rb +3 -3
  138. data/spec/model/association_reflection_spec.rb +83 -7
  139. data/spec/model/associations_spec.rb +393 -676
  140. data/spec/model/base_spec.rb +186 -116
  141. data/spec/model/dataset_methods_spec.rb +7 -27
  142. data/spec/model/eager_loading_spec.rb +343 -867
  143. data/spec/model/hooks_spec.rb +160 -79
  144. data/spec/model/model_spec.rb +118 -165
  145. data/spec/model/plugins_spec.rb +7 -13
  146. data/spec/model/record_spec.rb +138 -207
  147. data/spec/model/spec_helper.rb +10 -73
  148. metadata +14 -8
@@ -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))