sequel 1.5.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,50 +1,43 @@
1
1
  module Sequel
2
2
  class Model
3
- # Defines a table schema (see Schema::Generator for more information).
4
- #
5
- # This is only needed if you want to use the create_table or drop_table
6
- # methods.
7
- def self.set_schema(name = nil, &block)
8
- if name
9
- set_dataset(db[name])
10
- end
11
- @schema = Schema::Generator.new(db, &block)
12
- if @schema.primary_key_name
13
- set_primary_key @schema.primary_key_name
14
- end
15
- end
16
-
17
- # Returns table schema for direct descendant of Model.
18
- def self.schema
19
- @schema || ((superclass != Model) && (superclass.schema))
20
- end
21
-
22
- # Returns name of table.
23
- def self.table_name
24
- dataset.opts[:from].first
25
- end
26
-
27
- # Returns true if table exists, false otherwise.
28
- def self.table_exists?
29
- db.table_exists?(table_name)
30
- end
31
-
32
3
  # Creates table.
33
4
  def self.create_table
34
5
  db.create_table_sql_list(table_name, *schema.create_info).each {|s| db << s}
35
- @columns = nil
6
+ @db_schema = get_db_schema unless @@lazy_load_schema
36
7
  columns
37
8
  end
38
9
 
10
+ # Drops the table if it exists and then runs create_table.
11
+ def self.create_table!
12
+ drop_table if table_exists?
13
+ create_table
14
+ end
15
+
39
16
  # Drops table.
40
17
  def self.drop_table
41
18
  db.execute db.drop_table_sql(table_name)
42
19
  end
20
+
21
+ # Returns table schema created with set_schema for direct descendant of Model.
22
+ # Does not retreive schema information from the database, see db_schema if you
23
+ # want that.
24
+ def self.schema
25
+ @schema || ((superclass != Model) && (superclass.schema))
26
+ end
27
+
28
+ # Defines a table schema (see Schema::Generator for more information).
29
+ #
30
+ # This is only needed if you want to use the create_table or drop_table
31
+ # methods.
32
+ def self.set_schema(name = nil, &block)
33
+ set_dataset(db[name]) if name
34
+ @schema = Schema::Generator.new(db, &block)
35
+ set_primary_key(@schema.primary_key_name) if @schema.primary_key_name
36
+ end
43
37
 
44
- # Like create_table but invokes drop_table when table_exists? is true.
45
- def self.create_table!
46
- drop_table if table_exists?
47
- create_table
38
+ # Returns true if table exists, false otherwise.
39
+ def self.table_exists?
40
+ db.table_exists?(table_name)
48
41
  end
49
42
  end
50
43
  end
@@ -1,17 +1,3 @@
1
- class Array
2
- # Removes and returns the last member of the array if it is a hash. Otherwise,
3
- # an empty hash is returned This method is useful when writing methods that
4
- # take an options hash as the last parameter. For example:
5
- #
6
- # def validate_each(*args, &block)
7
- # opts = args.extract_options!
8
- # ...
9
- # end
10
- def extract_options!
11
- last.is_a?(Hash) ? pop : {}
12
- end
13
- end
14
-
15
1
  # The Validations module provides validation capabilities as a mixin. When
16
2
  # included into a class, it enhances the class with class and instance
17
3
  # methods for defining validations and validating class instances.
@@ -41,12 +27,15 @@ module Validation
41
27
  # Validates the object.
42
28
  def validate
43
29
  errors.clear
30
+ return false if before_validation == false
44
31
  self.class.validate(self)
32
+ after_validation
33
+ nil
45
34
  end
46
35
 
47
36
  # Validates the object and returns true if no errors are reported.
48
37
  def valid?
49
- validate
38
+ return false if validate == false
50
39
  errors.empty?
51
40
  end
52
41
 
@@ -57,9 +46,9 @@ module Validation
57
46
  @errors = Hash.new {|h, k| h[k] = []}
58
47
  end
59
48
 
60
- # Returns true if no errors are stored.
61
- def empty?
62
- @errors.empty?
49
+ # Adds an error for the given attribute.
50
+ def add(att, msg)
51
+ @errors[att] << msg
63
52
  end
64
53
 
65
54
  # Clears all errors.
@@ -67,25 +56,14 @@ module Validation
67
56
  @errors.clear
68
57
  end
69
58
 
70
- # Returns size of errors array
71
- def size
72
- @errors.size
73
- end
74
-
75
59
  # Iterates over errors
76
60
  def each(&block)
77
61
  @errors.each(&block)
78
62
  end
79
63
 
80
- # Returns the errors for the given attribute.
81
- def on(att)
82
- @errors[att]
83
- end
84
- alias_method :[], :on
85
-
86
- # Adds an error for the given attribute.
87
- def add(att, msg)
88
- @errors[att] << msg
64
+ # Returns true if no errors are stored.
65
+ def empty?
66
+ @errors.empty?
89
67
  end
90
68
 
91
69
  # Returns an array of fully-formatted error messages.
@@ -95,6 +73,17 @@ module Validation
95
73
  m
96
74
  end
97
75
  end
76
+
77
+ # Returns the errors for the given attribute.
78
+ def on(att)
79
+ @errors[att]
80
+ end
81
+ alias_method :[], :on
82
+
83
+ # Returns size of errors array
84
+ def size
85
+ @errors.size
86
+ end
98
87
  end
99
88
 
100
89
  # The Generator class is used to generate validation definitions using
@@ -114,6 +103,16 @@ module Validation
114
103
 
115
104
  # Validation class methods.
116
105
  module ClassMethods
106
+ # Returns true if validations are defined.
107
+ def has_validations?
108
+ !validations.empty?
109
+ end
110
+
111
+ # Instructs the model to skip validations defined in superclasses
112
+ def skip_superclass_validations
113
+ @skip_superclass_validations = true
114
+ end
115
+
117
116
  # Defines validations by converting a longhand block into a series of
118
117
  # shorthand definitions. For example:
119
118
  #
@@ -135,16 +134,6 @@ module Validation
135
134
  Generator.new(self, &block)
136
135
  end
137
136
 
138
- # Returns the validations hash for the class.
139
- def validations
140
- @validations ||= Hash.new {|h, k| h[k] = []}
141
- end
142
-
143
- # Returns true if validations are defined.
144
- def has_validations?
145
- !validations.empty?
146
- end
147
-
148
137
  # Validates the given instance.
149
138
  def validate(o)
150
139
  if superclass.respond_to?(:validate) && !@skip_superclass_validations
@@ -156,21 +145,6 @@ module Validation
156
145
  end
157
146
  end
158
147
 
159
- def skip_superclass_validations
160
- @skip_superclass_validations = true
161
- end
162
-
163
- # Adds a validation for each of the given attributes using the supplied
164
- # block. The block must accept three arguments: instance, attribute and
165
- # value, e.g.:
166
- #
167
- # validates_each :name, :password do |object, attribute, value|
168
- # object.errors[attribute] << 'is not nice' unless value.nice?
169
- # end
170
- def validates_each(*atts, &block)
171
- atts.each {|a| validations[a] << block}
172
- end
173
-
174
148
  # Validates acceptance of an attribute.
175
149
  def validates_acceptance_of(*atts)
176
150
  opts = {
@@ -198,6 +172,17 @@ module Validation
198
172
  end
199
173
  end
200
174
 
175
+ # Adds a validation for each of the given attributes using the supplied
176
+ # block. The block must accept three arguments: instance, attribute and
177
+ # value, e.g.:
178
+ #
179
+ # validates_each :name, :password do |object, attribute, value|
180
+ # object.errors[attribute] << 'is not nice' unless value.nice?
181
+ # end
182
+ def validates_each(*atts, &block)
183
+ atts.each {|a| validations[a] << block}
184
+ end
185
+
201
186
  # Validates the format of an attribute.
202
187
  def validates_format_of(*atts)
203
188
  opts = {
@@ -239,20 +224,23 @@ module Validation
239
224
  end
240
225
  end
241
226
 
242
- NUMBER_RE = /^\d*\.{0,1}\d+$/
243
- INTEGER_RE = /\A[+-]?\d+\Z/
244
-
245
227
  # Validates whether an attribute is a number.
246
228
  def validates_numericality_of(*atts)
247
229
  opts = {
248
230
  :message => 'is not a number',
249
231
  }.merge!(atts.extract_options!)
250
232
 
251
- re = opts[:only_integer] ? INTEGER_RE : NUMBER_RE
252
-
253
233
  validates_each(*atts) do |o, a, v|
254
234
  next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank])
255
- o.errors[a] << opts[:message] unless v.to_s =~ re
235
+ begin
236
+ if opts[:only_integer]
237
+ Kernel.Integer(v.to_s)
238
+ else
239
+ Kernel.Float(v.to_s)
240
+ end
241
+ rescue
242
+ o.errors[a] << opts[:message]
243
+ end
256
244
  end
257
245
  end
258
246
 
@@ -297,17 +285,10 @@ module Validation
297
285
  o.errors[a] << opts[:message] unless allow
298
286
  end
299
287
  end
300
- end
301
- end
302
288
 
303
- module Sequel
304
- class Model
305
- include Validation
306
-
307
- alias_method :save!, :save
308
- def save(*args)
309
- return false unless valid?
310
- save!(*args)
289
+ # Returns the validations hash for the class.
290
+ def validations
291
+ @validations ||= Hash.new {|h, k| h[k] = []}
311
292
  end
312
293
  end
313
294
  end
@@ -0,0 +1,85 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe Sequel::Model::Associations::AssociationReflection, "#associated_class" do
4
+ before do
5
+ @c = Class.new(Sequel::Model)
6
+ class ParParent < Sequel::Model; end
7
+ end
8
+
9
+ it "should use the :class value if present" do
10
+ @c.many_to_one :c, :class=>ParParent
11
+ @c.association_reflection(:c).should include(:class)
12
+ @c.association_reflection(:c).associated_class.should == ParParent
13
+ end
14
+ it "should figure out the class if the :class value is not present" do
15
+ @c.many_to_one :c, :class=>'ParParent'
16
+ @c.association_reflection(:c).should_not include(:class)
17
+ @c.association_reflection(:c).associated_class.should == ParParent
18
+ end
19
+ end
20
+
21
+ describe Sequel::Model::Associations::AssociationReflection, "#associated_primary_key" do
22
+ before do
23
+ @c = Class.new(Sequel::Model)
24
+ class ParParent < Sequel::Model; end
25
+ end
26
+
27
+ it "should use the :right_primary_key value if present" do
28
+ @c.many_to_one :c, :class=>ParParent, :associated_primary_key=>:blah__blah
29
+ @c.association_reflection(:c).should include(:associated_primary_key)
30
+ @c.association_reflection(:c).associated_primary_key.should == :blah__blah
31
+ end
32
+ it "should use the associated table's primary key if :associated_primary_key is not present" do
33
+ @c.many_to_one :c, :class=>'ParParent'
34
+ @c.association_reflection(:c).should_not include(:associated_primary_key)
35
+ @c.association_reflection(:c).associated_primary_key.should == :id
36
+ end
37
+ end
38
+
39
+ describe Sequel::Model::Associations::AssociationReflection, "#reciprocal" do
40
+ it "should use the :reciprocal value if present" do
41
+ @c = Class.new(Sequel::Model)
42
+ @d = Class.new(Sequel::Model)
43
+ @c.many_to_one :c, :class=>@d, :reciprocal=>:@xx
44
+ @c.association_reflection(:c).should include(:reciprocal)
45
+ @c.association_reflection(:c).reciprocal.should == :@xx
46
+ end
47
+
48
+ it "should figure out the reciprocal if the :reciprocal value is not present" do
49
+ class ParParent < Sequel::Model; end
50
+ class ParParentTwo < Sequel::Model; end
51
+ class ParParentThree < Sequel::Model; end
52
+ ParParent.many_to_one :par_parent_two
53
+ ParParentTwo.one_to_many :par_parents
54
+ ParParent.many_to_many :par_parent_threes
55
+ ParParentThree.many_to_many :par_parents
56
+
57
+ ParParent.association_reflection(:par_parent_two).should_not include(:reciprocal)
58
+ ParParent.association_reflection(:par_parent_two).reciprocal.should == :@par_parents
59
+ ParParentTwo.association_reflection(:par_parents).should_not include(:reciprocal)
60
+ ParParentTwo.association_reflection(:par_parents).reciprocal.should == :@par_parent_two
61
+ ParParent.association_reflection(:par_parent_threes).should_not include(:reciprocal)
62
+ ParParent.association_reflection(:par_parent_threes).reciprocal.should == :@par_parents
63
+ ParParentThree.association_reflection(:par_parents).should_not include(:reciprocal)
64
+ ParParentThree.association_reflection(:par_parents).reciprocal.should == :@par_parent_threes
65
+ end
66
+ end
67
+
68
+ describe Sequel::Model::Associations::AssociationReflection, "#select" do
69
+ before do
70
+ @c = Class.new(Sequel::Model)
71
+ class ParParent < Sequel::Model; end
72
+ end
73
+
74
+ it "should use the :select value if present" do
75
+ @c.many_to_one :c, :class=>ParParent, :select=>[:par_parents__id]
76
+ @c.association_reflection(:c).should include(:select)
77
+ @c.association_reflection(:c).select.should == [:par_parents__id]
78
+ end
79
+ it "should use the associated_table.* if :select is not present" do
80
+ @c.many_to_one :c, :class=>'ParParent'
81
+ @c.association_reflection(:c).should_not include(:select)
82
+ @c.association_reflection(:c).select.should == :par_parents.*
83
+ end
84
+ end
85
+
@@ -11,9 +11,9 @@ describe Sequel::Model, "associate" do
11
11
  klass.associate :one_to_many, :par_parent1s, :class=>'ParParent'
12
12
  klass.associate :many_to_many, :par_parent2s, :class=>:ParParent
13
13
 
14
- klass.send(:associated_class, klass.association_reflection(:"par_parent0")).should == ParParent
15
- klass.send(:associated_class, klass.association_reflection(:"par_parent1s")).should == ParParent
16
- klass.send(:associated_class, klass.association_reflection(:"par_parent2s")).should == ParParent
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
17
  end
18
18
  end
19
19
 
@@ -42,7 +42,7 @@ describe Sequel::Model, "many_to_one" do
42
42
  p.class.should == @c2
43
43
  p.values.should == {:x => 1, :id => 1}
44
44
 
45
- MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (id = 234) LIMIT 1"]
45
+ MODEL_DB.sqls.should == ["SELECT nodes.* FROM nodes WHERE (id = 234) LIMIT 1"]
46
46
  end
47
47
 
48
48
  it "should use implicit class if omitted" do
@@ -55,7 +55,7 @@ describe Sequel::Model, "many_to_one" do
55
55
  p = d.par_parent
56
56
  p.class.should == ParParent
57
57
 
58
- MODEL_DB.sqls.should == ["SELECT * FROM par_parents WHERE (id = 234) LIMIT 1"]
58
+ MODEL_DB.sqls.should == ["SELECT par_parents.* FROM par_parents WHERE (id = 234) LIMIT 1"]
59
59
  end
60
60
 
61
61
  it "should use class inside module if given as a string" do
@@ -70,7 +70,7 @@ describe Sequel::Model, "many_to_one" do
70
70
  p = d.par_parent
71
71
  p.class.should == Par::Parent
72
72
 
73
- MODEL_DB.sqls.should == ["SELECT * FROM parents WHERE (id = 234) LIMIT 1"]
73
+ MODEL_DB.sqls.should == ["SELECT parents.* FROM parents WHERE (id = 234) LIMIT 1"]
74
74
  end
75
75
 
76
76
  it "should use explicit key if given" do
@@ -81,7 +81,13 @@ describe Sequel::Model, "many_to_one" do
81
81
  p.class.should == @c2
82
82
  p.values.should == {:x => 1, :id => 1}
83
83
 
84
- MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (id = 567) LIMIT 1"]
84
+ MODEL_DB.sqls.should == ["SELECT nodes.* FROM nodes WHERE (id = 567) LIMIT 1"]
85
+ end
86
+
87
+ it "should use :select option if given" do
88
+ @c2.many_to_one :parent, :class => @c2, :key => :blah, :select=>[:id, :name]
89
+ @c2.new(:id => 1, :blah => 567).parent
90
+ MODEL_DB.sqls.should == ["SELECT id, name FROM nodes WHERE (id = 567) LIMIT 1"]
85
91
  end
86
92
 
87
93
  it "should return nil if key value is nil" do
@@ -101,9 +107,9 @@ describe Sequel::Model, "many_to_one" do
101
107
  d = @c2.new(:id => 1, :parent_id=>555)
102
108
  MODEL_DB.sqls.should == []
103
109
  d.parent.should == nil
104
- MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (id = 555) LIMIT 1']
110
+ MODEL_DB.sqls.should == ['SELECT nodes.* FROM nodes WHERE (id = 555) LIMIT 1']
105
111
  d.parent.should == nil
106
- MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (id = 555) LIMIT 1']
112
+ MODEL_DB.sqls.should == ['SELECT nodes.* FROM nodes WHERE (id = 555) LIMIT 1']
107
113
  end
108
114
 
109
115
  it "should define a setter method" do
@@ -142,7 +148,7 @@ describe Sequel::Model, "many_to_one" do
142
148
  ds = @c2.dataset
143
149
  def ds.fetch_rows(sql, &block); MODEL_DB.sqls << sql; yield({:id=>234}) end
144
150
  e = d.parent
145
- MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (id = 234) LIMIT 1"]
151
+ MODEL_DB.sqls.should == ["SELECT nodes.* FROM nodes WHERE (id = 234) LIMIT 1"]
146
152
  d.instance_variable_get("@parent").should == e
147
153
  end
148
154
 
@@ -176,7 +182,7 @@ describe Sequel::Model, "many_to_one" do
176
182
  d.parent_id = 234
177
183
  d.instance_variable_set(:@parent, 42)
178
184
  d.parent(true).should_not == 42
179
- MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (id = 234) LIMIT 1"]
185
+ MODEL_DB.sqls.should == ["SELECT nodes.* FROM nodes WHERE (id = 234) LIMIT 1"]
180
186
  end
181
187
 
182
188
  it "should have the setter add to the reciprocal one_to_many cached association list if it exists" do
@@ -192,16 +198,16 @@ describe Sequel::Model, "many_to_one" do
192
198
  MODEL_DB.sqls.should == []
193
199
  d.parent = e
194
200
  e.children.should_not(include(d))
195
- MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (parent_id = 2)']
201
+ MODEL_DB.sqls.should == ['SELECT nodes.* FROM nodes WHERE (parent_id = 2)']
196
202
 
197
203
  MODEL_DB.reset
198
204
  d = @c2.new(:id => 1)
199
205
  e = @c2.new(:id => 2)
200
206
  e.children.should_not(include(d))
201
- MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (parent_id = 2)']
207
+ MODEL_DB.sqls.should == ['SELECT nodes.* FROM nodes WHERE (parent_id = 2)']
202
208
  d.parent = e
203
209
  e.children.should(include(d))
204
- MODEL_DB.sqls.should == ['SELECT * FROM nodes WHERE (parent_id = 2)']
210
+ MODEL_DB.sqls.should == ['SELECT nodes.* FROM nodes WHERE (parent_id = 2)']
205
211
  end
206
212
 
207
213
  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
@@ -238,7 +244,7 @@ describe Sequel::Model, "many_to_one" do
238
244
  ds = @c2.dataset
239
245
  def ds.fetch_rows(sql, &block); MODEL_DB.sqls << sql; yield({:id=>234}) end
240
246
  e = d.parent
241
- MODEL_DB.sqls.should == ["SELECT * FROM nodes WHERE (id = 234) LIMIT 1"]
247
+ MODEL_DB.sqls.should == ["SELECT nodes.* FROM nodes WHERE (id = 234) LIMIT 1"]
242
248
  d.instance_variable_get("@parent").should == e
243
249
  end
244
250
  end
@@ -282,7 +288,7 @@ describe Sequel::Model, "one_to_many" do
282
288
  n = @c2.new(:id => 1234)
283
289
  a = n.attributes_dataset
284
290
  a.should be_a_kind_of(Sequel::Dataset)
285
- a.sql.should == 'SELECT * FROM attributes WHERE (node_id = 1234)'
291
+ a.sql.should == 'SELECT attributes.* FROM attributes WHERE (node_id = 1234)'
286
292
  end
287
293
 
288
294
  it "should use implicit class if omitted" do
@@ -294,7 +300,7 @@ describe Sequel::Model, "one_to_many" do
294
300
  n = @c2.new(:id => 1234)
295
301
  v = n.historical_values_dataset
296
302
  v.should be_a_kind_of(Sequel::Dataset)
297
- v.sql.should == 'SELECT * FROM historical_values WHERE (node_id = 1234)'
303
+ v.sql.should == 'SELECT historical_values.* FROM historical_values WHERE (node_id = 1234)'
298
304
  v.model_classes.should == {nil => HistoricalValue}
299
305
  end
300
306
 
@@ -309,7 +315,7 @@ describe Sequel::Model, "one_to_many" do
309
315
  n = @c2.new(:id => 1234)
310
316
  v = n.historical_values_dataset
311
317
  v.should be_a_kind_of(Sequel::Dataset)
312
- v.sql.should == 'SELECT * FROM values WHERE (node_id = 1234)'
318
+ v.sql.should == 'SELECT values.* FROM values WHERE (node_id = 1234)'
313
319
  v.model_classes.should == {nil => Historical::Value}
314
320
  end
315
321
 
@@ -319,7 +325,7 @@ describe Sequel::Model, "one_to_many" do
319
325
  n = @c2.new(:id => 1234)
320
326
  a = n.attributes_dataset
321
327
  a.should be_a_kind_of(Sequel::Dataset)
322
- a.sql.should == 'SELECT * FROM attributes WHERE (nodeid = 1234)'
328
+ a.sql.should == 'SELECT attributes.* FROM attributes WHERE (nodeid = 1234)'
323
329
  end
324
330
 
325
331
  it "should define an add_ method" do
@@ -344,18 +350,25 @@ describe Sequel::Model, "one_to_many" do
344
350
  MODEL_DB.sqls.should == ['UPDATE attributes SET node_id = NULL WHERE (id = 2345)']
345
351
  end
346
352
 
353
+ it "should support a select option" do
354
+ @c2.one_to_many :attributes, :class => @c1, :select => [:id, :name]
355
+
356
+ n = @c2.new(:id => 1234)
357
+ n.attributes_dataset.sql.should == "SELECT id, name FROM attributes WHERE (node_id = 1234)"
358
+ end
359
+
347
360
  it "should support an order option" do
348
361
  @c2.one_to_many :attributes, :class => @c1, :order => :kind
349
362
 
350
363
  n = @c2.new(:id => 1234)
351
- n.attributes_dataset.sql.should == "SELECT * FROM attributes WHERE (node_id = 1234) ORDER BY kind"
364
+ n.attributes_dataset.sql.should == "SELECT attributes.* FROM attributes WHERE (node_id = 1234) ORDER BY kind"
352
365
  end
353
366
 
354
367
  it "should support an array for the order option" do
355
368
  @c2.one_to_many :attributes, :class => @c1, :order => [:kind1, :kind2]
356
369
 
357
370
  n = @c2.new(:id => 1234)
358
- n.attributes_dataset.sql.should == "SELECT * FROM attributes WHERE (node_id = 1234) ORDER BY kind1, kind2"
371
+ n.attributes_dataset.sql.should == "SELECT attributes.* FROM attributes WHERE (node_id = 1234) ORDER BY kind1, kind2"
359
372
  end
360
373
 
361
374
  it "should return array with all members of the association" do
@@ -368,7 +381,7 @@ describe Sequel::Model, "one_to_many" do
368
381
  atts.first.should be_a_kind_of(@c1)
369
382
  atts.first.values.should == {}
370
383
 
371
- MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (node_id = 1234)']
384
+ MODEL_DB.sqls.should == ['SELECT attributes.* FROM attributes WHERE (node_id = 1234)']
372
385
  end
373
386
 
374
387
  it "should accept a block" do
@@ -383,7 +396,7 @@ describe Sequel::Model, "one_to_many" do
383
396
  atts.first.should be_a_kind_of(@c1)
384
397
  atts.first.values.should == {}
385
398
 
386
- MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (node_id = 1234) AND (xxx IS NULL)']
399
+ MODEL_DB.sqls.should == ['SELECT attributes.* FROM attributes WHERE ((node_id = 1234) AND (xxx IS NULL))']
387
400
  end
388
401
 
389
402
  it "should support order option with block" do
@@ -398,7 +411,7 @@ describe Sequel::Model, "one_to_many" do
398
411
  atts.first.should be_a_kind_of(@c1)
399
412
  atts.first.values.should == {}
400
413
 
401
- MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (node_id = 1234) AND (xxx IS NULL) ORDER BY kind']
414
+ MODEL_DB.sqls.should == ['SELECT attributes.* FROM attributes WHERE ((node_id = 1234) AND (xxx IS NULL)) ORDER BY kind']
402
415
  end
403
416
 
404
417
  it "should set cached instance variable when accessed" do
@@ -409,7 +422,7 @@ describe Sequel::Model, "one_to_many" do
409
422
  n.instance_variables.include?("@attributes").should == false
410
423
  atts = n.attributes
411
424
  atts.should == n.instance_variable_get("@attributes")
412
- MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (node_id = 1234)']
425
+ MODEL_DB.sqls.should == ['SELECT attributes.* FROM attributes WHERE (node_id = 1234)']
413
426
  end
414
427
 
415
428
  it "should use cached instance variable if available" do
@@ -429,7 +442,7 @@ describe Sequel::Model, "one_to_many" do
429
442
  MODEL_DB.reset
430
443
  n.instance_variable_set(:@attributes, 42)
431
444
  n.attributes(true).should_not == 42
432
- MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (node_id = 1234)']
445
+ MODEL_DB.sqls.should == ['SELECT attributes.* FROM attributes WHERE (node_id = 1234)']
433
446
  end
434
447
 
435
448
  it "should add item to cached instance variable if it exists when calling add_" do
@@ -488,7 +501,7 @@ describe Sequel::Model, "one_to_many" do
488
501
  atts.first.should be_a_kind_of(@c1)
489
502
  atts.first.values.should == {}
490
503
 
491
- MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (node_id = 1234)']
504
+ MODEL_DB.sqls.should == ['SELECT attributes.* FROM attributes WHERE (node_id = 1234)']
492
505
  end
493
506
 
494
507
  it "should populate the reciprocal many_to_one instance variable when loading the one_to_many association" do
@@ -497,7 +510,7 @@ describe Sequel::Model, "one_to_many" do
497
510
 
498
511
  n = @c2.new(:id => 1234)
499
512
  atts = n.attributes
500
- MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (node_id = 1234)']
513
+ MODEL_DB.sqls.should == ['SELECT attributes.* FROM attributes WHERE (node_id = 1234)']
501
514
  atts.should be_a_kind_of(Array)
502
515
  atts.size.should == 1
503
516
  atts.first.should be_a_kind_of(@c1)
@@ -512,7 +525,7 @@ describe Sequel::Model, "one_to_many" do
512
525
 
513
526
  n = @c2.new(:id => 1234)
514
527
  atts = n.attributes
515
- MODEL_DB.sqls.should == ['SELECT * FROM attributes WHERE (node_id = 1234)']
528
+ MODEL_DB.sqls.should == ['SELECT attributes.* FROM attributes WHERE (node_id = 1234)']
516
529
  atts.should be_a_kind_of(Array)
517
530
  atts.size.should == 1
518
531
  atts.first.should be_a_kind_of(@c1)
@@ -521,6 +534,55 @@ describe Sequel::Model, "one_to_many" do
521
534
 
522
535
  MODEL_DB.sqls.length.should == 1
523
536
  end
537
+
538
+ it "should have an remove_all_ method that removes all associations" do
539
+ @c2.one_to_many :attributes, :class => @c1
540
+ @c2.new(:id => 1234).remove_all_attributes
541
+ MODEL_DB.sqls.first.should == 'UPDATE attributes SET node_id = NULL WHERE (node_id = 1234)'
542
+ end
543
+
544
+ it "remove_all should set the cached instance variable to []" do
545
+ @c2.one_to_many :attributes, :class => @c1
546
+ node = @c2.new(:id => 1234)
547
+ node.remove_all_attributes
548
+ node.instance_variable_get(:@attributes).should == []
549
+ end
550
+
551
+ it "remove_all should return the array of previously associated items if the cached instance variable exists" do
552
+ @c2.one_to_many :attributes, :class => @c1
553
+ attrib = @c1.new(:id=>3)
554
+ node = @c2.new(:id => 1234)
555
+ d = @c1.dataset
556
+ def d.fetch_rows(s); end
557
+ node.attributes.should == []
558
+ def attrib.save!; end
559
+ node.add_attribute(attrib)
560
+ node.instance_variable_get(:@attributes).should == [attrib]
561
+ node.remove_all_attributes.should == [attrib]
562
+ end
563
+
564
+ it "remove_all should return nil if the cached instance variable does not exist" do
565
+ @c2.one_to_many :attributes, :class => @c1
566
+ @c2.new(:id => 1234).remove_all_attributes.should == nil
567
+ end
568
+
569
+ it "remove_all should remove the current item from all reciprocal instance varaibles if it cached instance variable exists" do
570
+ @c2.one_to_many :attributes, :class => @c1
571
+ @c1.many_to_one :node, :class => @c2
572
+ d = @c1.dataset
573
+ def d.fetch_rows(s); end
574
+ d = @c2.dataset
575
+ def d.fetch_rows(s); end
576
+ attrib = @c1.new(:id=>3)
577
+ node = @c2.new(:id => 1234)
578
+ node.attributes.should == []
579
+ attrib.node.should == nil
580
+ def attrib.save!; end
581
+ node.add_attribute(attrib)
582
+ attrib.instance_variable_get(:@node).should == node
583
+ node.remove_all_attributes
584
+ attrib.instance_variable_get(:@node).should == :null
585
+ end
524
586
  end
525
587
 
526
588
  describe Sequel::Model, "many_to_many" do
@@ -559,9 +621,7 @@ describe Sequel::Model, "many_to_many" do
559
621
  n = @c2.new(:id => 1234)
560
622
  a = n.attributes_dataset
561
623
  a.should be_a_kind_of(Sequel::Dataset)
562
- ['SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)',
563
- 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.node_id = 1234) AND (attributes_nodes.attribute_id = attributes.id)'
564
- ].should(include(a.sql))
624
+ a.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234))'
565
625
  end
566
626
 
567
627
  it "should use implicit class if omitted" do
@@ -573,9 +633,7 @@ describe Sequel::Model, "many_to_many" do
573
633
  n = @c2.new(:id => 1234)
574
634
  a = n.tags_dataset
575
635
  a.should be_a_kind_of(Sequel::Dataset)
576
- ['SELECT tags.* FROM tags INNER JOIN nodes_tags ON (nodes_tags.tag_id = tags.id) AND (nodes_tags.node_id = 1234)',
577
- 'SELECT tags.* FROM tags INNER JOIN nodes_tags ON (nodes_tags.node_id = 1234) AND (nodes_tags.tag_id = tags.id)'
578
- ].should(include(a.sql))
636
+ a.sql.should == 'SELECT tags.* FROM tags INNER JOIN nodes_tags ON ((nodes_tags.tag_id = tags.id) AND (nodes_tags.node_id = 1234))'
579
637
  end
580
638
 
581
639
  it "should use class inside module if given as a string" do
@@ -589,9 +647,7 @@ describe Sequel::Model, "many_to_many" do
589
647
  n = @c2.new(:id => 1234)
590
648
  a = n.tags_dataset
591
649
  a.should be_a_kind_of(Sequel::Dataset)
592
- ['SELECT tags.* FROM tags INNER JOIN nodes_tags ON (nodes_tags.tag_id = tags.id) AND (nodes_tags.node_id = 1234)',
593
- 'SELECT tags.* FROM tags INNER JOIN nodes_tags ON (nodes_tags.node_id = 1234) AND (nodes_tags.tag_id = tags.id)'
594
- ].should(include(a.sql))
650
+ a.sql.should == 'SELECT tags.* FROM tags INNER JOIN nodes_tags ON ((nodes_tags.tag_id = tags.id) AND (nodes_tags.node_id = 1234))'
595
651
  end
596
652
 
597
653
  it "should use explicit key values and join table if given" do
@@ -600,9 +656,7 @@ describe Sequel::Model, "many_to_many" do
600
656
  n = @c2.new(:id => 1234)
601
657
  a = n.attributes_dataset
602
658
  a.should be_a_kind_of(Sequel::Dataset)
603
- ['SELECT attributes.* FROM attributes INNER JOIN attribute2node ON (attribute2node.nodeid = 1234) AND (attribute2node.attributeid = attributes.id)',
604
- 'SELECT attributes.* FROM attributes INNER JOIN attribute2node ON (attribute2node.attributeid = attributes.id) AND (attribute2node.nodeid = 1234)'
605
- ].should(include(a.sql))
659
+ a.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attribute2node ON ((attribute2node.attributeid = attributes.id) AND (attribute2node.nodeid = 1234))'
606
660
  end
607
661
 
608
662
  it "should support an order option" do
@@ -611,9 +665,7 @@ describe Sequel::Model, "many_to_many" do
611
665
  n = @c2.new(:id => 1234)
612
666
  a = n.attributes_dataset
613
667
  a.should be_a_kind_of(Sequel::Dataset)
614
- ['SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234) ORDER BY blah',
615
- 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.node_id = 1234) AND (attributes_nodes.attribute_id = attributes.id) ORDER BY blah'
616
- ].should(include(a.sql))
668
+ 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'
617
669
  end
618
670
 
619
671
  it "should support an array for the order option" do
@@ -622,9 +674,7 @@ describe Sequel::Model, "many_to_many" do
622
674
  n = @c2.new(:id => 1234)
623
675
  a = n.attributes_dataset
624
676
  a.should be_a_kind_of(Sequel::Dataset)
625
- ['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',
626
- 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.node_id = 1234) AND (attributes_nodes.attribute_id = attributes.id) ORDER BY blah1, blah2'
627
- ].should(include(a.sql))
677
+ 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'
628
678
  end
629
679
 
630
680
  it "should support a select option" do
@@ -633,9 +683,7 @@ describe Sequel::Model, "many_to_many" do
633
683
  n = @c2.new(:id => 1234)
634
684
  a = n.attributes_dataset
635
685
  a.should be_a_kind_of(Sequel::Dataset)
636
- ['SELECT blah FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)',
637
- 'SELECT blah FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.node_id = 1234) AND (attributes_nodes.attribute_id = attributes.id)'
638
- ].should(include(a.sql))
686
+ a.sql.should == 'SELECT blah FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234))'
639
687
  end
640
688
 
641
689
  it "should support an array for the select option" do
@@ -644,9 +692,7 @@ describe Sequel::Model, "many_to_many" do
644
692
  n = @c2.new(:id => 1234)
645
693
  a = n.attributes_dataset
646
694
  a.should be_a_kind_of(Sequel::Dataset)
647
- ['SELECT attributes.*, attribute_nodes.blah2 FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)',
648
- 'SELECT attributes.*, attribute_nodes.blah2 FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.node_id = 1234) AND (attributes_nodes.attribute_id = attributes.id)'
649
- ].should(include(a.sql))
695
+ 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))'
650
696
  end
651
697
 
652
698
  it "should accept a block" do
@@ -660,9 +706,7 @@ describe Sequel::Model, "many_to_many" do
660
706
  a.should be_a_kind_of(Array)
661
707
  a.size.should == 1
662
708
  a.first.should be_a_kind_of(@c1)
663
- ['SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234) WHERE (xxx = 555)',
664
- 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.node_id = 1234) AND (attributes_nodes.attribute_id = attributes.id) WHERE (xxx = 555)'
665
- ].should(include(MODEL_DB.sqls.first))
709
+ 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)'
666
710
  end
667
711
 
668
712
  it "should allow the order option while accepting a block" do
@@ -676,9 +720,7 @@ describe Sequel::Model, "many_to_many" do
676
720
  a.should be_a_kind_of(Array)
677
721
  a.size.should == 1
678
722
  a.first.should be_a_kind_of(@c1)
679
- ['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',
680
- 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.node_id = 1234) AND (attributes_nodes.attribute_id = attributes.id) WHERE (xxx = 555) ORDER BY blah1, blah2'
681
- ].should(include(MODEL_DB.sqls.first))
723
+ 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'
682
724
  end
683
725
 
684
726
  it "should define an add_ method" do
@@ -698,9 +740,7 @@ describe Sequel::Model, "many_to_many" do
698
740
  n = @c2.new(:id => 1234)
699
741
  a = @c1.new(:id => 2345)
700
742
  a.should == n.remove_attribute(a)
701
- ['DELETE FROM attributes_nodes WHERE (node_id = 1234) AND (attribute_id = 2345)',
702
- 'DELETE FROM attributes_nodes WHERE (attribute_id = 2345) AND (node_id = 1234)'
703
- ].should(include(MODEL_DB.sqls.first))
743
+ MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE ((node_id = 1234) AND (attribute_id = 2345))'
704
744
  end
705
745
 
706
746
  it "should provide an array with all members of the association" do
@@ -712,9 +752,7 @@ describe Sequel::Model, "many_to_many" do
712
752
  atts.size.should == 1
713
753
  atts.first.should be_a_kind_of(@c1)
714
754
 
715
- ['SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)',
716
- 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.node_id = 1234) AND (attributes_nodes.attribute_id = attributes.id)'
717
- ].should(include(MODEL_DB.sqls.first))
755
+ 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))'
718
756
  end
719
757
 
720
758
  it "should set cached instance variable when accessed" do
@@ -800,11 +838,55 @@ describe Sequel::Model, "many_to_many" do
800
838
  n = @c2.new(:id => 1234)
801
839
  a = n.attributes_dataset
802
840
  a.should be_a_kind_of(Sequel::Dataset)
803
- ['SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234)',
804
- 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.node_id = 1234) AND (attributes_nodes.attribute_id = attributes.id)'
805
- ].should(include(a.sql))
841
+ a.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON ((attributes_nodes.attribute_id = attributes.id) AND (attributes_nodes.node_id = 1234))'
806
842
  end
807
843
 
844
+ it "should have an remove_all_ method that removes all associations" do
845
+ @c2.many_to_many :attributes, :class => @c1
846
+ @c2.new(:id => 1234).remove_all_attributes
847
+ MODEL_DB.sqls.first.should == 'DELETE FROM attributes_nodes WHERE (node_id = 1234)'
848
+ end
849
+
850
+ it "remove_all should set the cached instance variable to []" do
851
+ @c2.many_to_many :attributes, :class => @c1
852
+ node = @c2.new(:id => 1234)
853
+ node.remove_all_attributes
854
+ node.instance_variable_get(:@attributes).should == []
855
+ end
856
+
857
+ it "remove_all should return the array of previously associated items if the cached instance variable exists" do
858
+ @c2.many_to_many :attributes, :class => @c1
859
+ attrib = @c1.new(:id=>3)
860
+ node = @c2.new(:id => 1234)
861
+ d = @c1.dataset
862
+ def d.fetch_rows(s); end
863
+ node.attributes.should == []
864
+ node.add_attribute(attrib)
865
+ node.instance_variable_get(:@attributes).should == [attrib]
866
+ node.remove_all_attributes.should == [attrib]
867
+ end
868
+
869
+ it "remove_all should return nil if the cached instance variable does not exist" do
870
+ @c2.many_to_many :attributes, :class => @c1
871
+ @c2.new(:id => 1234).remove_all_attributes.should == nil
872
+ end
873
+
874
+ it "remove_all should remove the current item from all reciprocal instance varaibles if it cached instance variable exists" do
875
+ @c2.many_to_many :attributes, :class => @c1
876
+ @c1.many_to_many :nodes, :class => @c2
877
+ d = @c1.dataset
878
+ def d.fetch_rows(s); end
879
+ d = @c2.dataset
880
+ def d.fetch_rows(s); end
881
+ attrib = @c1.new(:id=>3)
882
+ node = @c2.new(:id => 1234)
883
+ node.attributes.should == []
884
+ attrib.nodes.should == []
885
+ node.add_attribute(attrib)
886
+ attrib.instance_variable_get(:@nodes).should == [node]
887
+ node.remove_all_attributes
888
+ attrib.instance_variable_get(:@nodes).should == []
889
+ end
808
890
  end
809
891
 
810
892
  describe Sequel::Model, "all_association_reflections" do
@@ -821,14 +903,17 @@ describe Sequel::Model, "all_association_reflections" do
821
903
  @c1.associate :many_to_one, :parent, :class => @c1
822
904
  @c1.all_association_reflections.should == [{
823
905
  :type => :many_to_one, :name => :parent, :class_name => 'Node',
824
- :class => @c1, :key => :parent_id, :block => nil, :cache => true
906
+ :class => @c1, :key => :parent_id, :block => nil, :cache => true,
907
+ :graph_join_type=>:left_outer, :graph_conditions=>[], :eager_block => nil, :model => @c1
825
908
  }]
826
909
  @c1.associate :one_to_many, :children, :class => @c1
827
910
  @c1.all_association_reflections.sort_by{|x|x[:name].to_s}.should == [{
828
911
  :type => :one_to_many, :name => :children, :class_name => 'Node',
829
- :class => @c1, :key => :node_id, :block => nil, :cache => true}, {
912
+ :class => @c1, :key => :node_id, :block => nil, :cache => true,
913
+ :graph_join_type=>:left_outer, :graph_conditions=>[], :eager_block => nil, :model => @c1}, {
830
914
  :type => :many_to_one, :name => :parent, :class_name => 'Node',
831
- :class => @c1, :key => :parent_id, :block => nil, :cache => true}]
915
+ :class => @c1, :key => :parent_id, :block => nil, :cache => true,
916
+ :graph_join_type=>:left_outer, :graph_conditions=>[], :eager_block => nil, :model => @c1}]
832
917
  end
833
918
  end
834
919
 
@@ -849,12 +934,14 @@ describe Sequel::Model, "association_reflection" do
849
934
  @c1.associate :many_to_one, :parent, :class => @c1
850
935
  @c1.association_reflection(:parent).should == {
851
936
  :type => :many_to_one, :name => :parent, :class_name => 'Node',
852
- :class => @c1, :key => :parent_id, :block => nil, :cache => true
937
+ :class => @c1, :key => :parent_id, :block => nil, :cache => true,
938
+ :graph_join_type=>:left_outer, :graph_conditions=>[], :eager_block => nil, :model => @c1
853
939
  }
854
940
  @c1.associate :one_to_many, :children, :class => @c1
855
941
  @c1.association_reflection(:children).should == {
856
942
  :type => :one_to_many, :name => :children, :class_name => 'Node',
857
- :class => @c1, :key => :node_id, :block => nil, :cache => true
943
+ :class => @c1, :key => :node_id, :block => nil, :cache => true,
944
+ :graph_join_type=>:left_outer, :graph_conditions=>[], :eager_block => nil, :model => @c1
858
945
  }
859
946
  end
860
947
  end