sequel 2.11.0 → 2.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. data/CHANGELOG +168 -0
  2. data/README.rdoc +77 -95
  3. data/Rakefile +100 -80
  4. data/bin/sequel +2 -1
  5. data/doc/advanced_associations.rdoc +23 -32
  6. data/doc/cheat_sheet.rdoc +23 -40
  7. data/doc/dataset_filtering.rdoc +6 -6
  8. data/doc/prepared_statements.rdoc +22 -22
  9. data/doc/release_notes/2.12.0.txt +534 -0
  10. data/doc/schema.rdoc +3 -1
  11. data/doc/sharding.rdoc +8 -8
  12. data/doc/virtual_rows.rdoc +65 -0
  13. data/lib/sequel.rb +1 -1
  14. data/lib/{sequel_core → sequel}/adapters/ado.rb +3 -3
  15. data/lib/{sequel_core → sequel}/adapters/db2.rb +0 -0
  16. data/lib/{sequel_core → sequel}/adapters/dbi.rb +1 -1
  17. data/lib/{sequel_core → sequel}/adapters/do.rb +9 -5
  18. data/lib/{sequel_core → sequel}/adapters/do/mysql.rb +1 -1
  19. data/lib/{sequel_core → sequel}/adapters/do/postgres.rb +1 -1
  20. data/lib/{sequel_core → sequel}/adapters/do/sqlite.rb +1 -1
  21. data/lib/{sequel_core → sequel}/adapters/firebird.rb +84 -80
  22. data/lib/{sequel_core → sequel}/adapters/informix.rb +1 -1
  23. data/lib/{sequel_core → sequel}/adapters/jdbc.rb +21 -14
  24. data/lib/{sequel_core → sequel}/adapters/jdbc/h2.rb +14 -13
  25. data/lib/{sequel_core → sequel}/adapters/jdbc/mysql.rb +1 -1
  26. data/lib/{sequel_core → sequel}/adapters/jdbc/oracle.rb +1 -1
  27. data/lib/{sequel_core → sequel}/adapters/jdbc/postgresql.rb +1 -1
  28. data/lib/{sequel_core → sequel}/adapters/jdbc/sqlite.rb +1 -1
  29. data/lib/{sequel_core → sequel}/adapters/mysql.rb +60 -39
  30. data/lib/{sequel_core → sequel}/adapters/odbc.rb +8 -4
  31. data/lib/{sequel_core → sequel}/adapters/openbase.rb +0 -0
  32. data/lib/{sequel_core → sequel}/adapters/oracle.rb +38 -7
  33. data/lib/{sequel_core → sequel}/adapters/postgres.rb +24 -24
  34. data/lib/{sequel_core → sequel}/adapters/shared/mssql.rb +5 -5
  35. data/lib/{sequel_core → sequel}/adapters/shared/mysql.rb +126 -71
  36. data/lib/{sequel_core → sequel}/adapters/shared/oracle.rb +7 -10
  37. data/lib/{sequel_core → sequel}/adapters/shared/postgres.rb +159 -125
  38. data/lib/{sequel_core → sequel}/adapters/shared/progress.rb +1 -2
  39. data/lib/{sequel_core → sequel}/adapters/shared/sqlite.rb +72 -67
  40. data/lib/{sequel_core → sequel}/adapters/sqlite.rb +11 -7
  41. data/lib/{sequel_core → sequel}/adapters/utils/date_format.rb +0 -0
  42. data/lib/{sequel_core → sequel}/adapters/utils/stored_procedures.rb +0 -0
  43. data/lib/{sequel_core → sequel}/adapters/utils/unsupported.rb +19 -0
  44. data/lib/{sequel_core → sequel}/connection_pool.rb +7 -5
  45. data/lib/sequel/core.rb +221 -0
  46. data/lib/{sequel_core → sequel}/core_sql.rb +91 -49
  47. data/lib/{sequel_core → sequel}/database.rb +264 -149
  48. data/lib/{sequel_core/schema/generator.rb → sequel/database/schema_generator.rb} +6 -2
  49. data/lib/{sequel_core/database/schema.rb → sequel/database/schema_methods.rb} +12 -12
  50. data/lib/sequel/database/schema_sql.rb +224 -0
  51. data/lib/{sequel_core → sequel}/dataset.rb +78 -236
  52. data/lib/{sequel_core → sequel}/dataset/convenience.rb +99 -61
  53. data/lib/{sequel_core/object_graph.rb → sequel/dataset/graph.rb} +16 -14
  54. data/lib/{sequel_core → sequel}/dataset/prepared_statements.rb +1 -1
  55. data/lib/{sequel_core → sequel}/dataset/sql.rb +150 -99
  56. data/lib/sequel/deprecated.rb +593 -0
  57. data/lib/sequel/deprecated_migration.rb +91 -0
  58. data/lib/sequel/exceptions.rb +48 -0
  59. data/lib/sequel/extensions/blank.rb +42 -0
  60. data/lib/{sequel_model → sequel/extensions}/inflector.rb +8 -1
  61. data/lib/{sequel_core → sequel/extensions}/migration.rb +1 -1
  62. data/lib/{sequel_core/dataset → sequel/extensions}/pagination.rb +0 -0
  63. data/lib/{sequel_core → sequel/extensions}/pretty_table.rb +7 -0
  64. data/lib/{sequel_core/dataset → sequel/extensions}/query.rb +7 -0
  65. data/lib/sequel/extensions/string_date_time.rb +47 -0
  66. data/lib/sequel/metaprogramming.rb +43 -0
  67. data/lib/sequel/model.rb +110 -0
  68. data/lib/sequel/model/associations.rb +1300 -0
  69. data/lib/sequel/model/base.rb +937 -0
  70. data/lib/sequel/model/deprecated.rb +204 -0
  71. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  72. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  73. data/lib/sequel/model/deprecated_validations.rb +388 -0
  74. data/lib/sequel/model/errors.rb +39 -0
  75. data/lib/{sequel_model → sequel/model}/exceptions.rb +4 -4
  76. data/lib/sequel/model/inflections.rb +208 -0
  77. data/lib/sequel/model/plugins.rb +76 -0
  78. data/lib/sequel/plugins/caching.rb +122 -0
  79. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  80. data/lib/sequel/plugins/schema.rb +53 -0
  81. data/lib/sequel/plugins/serialization.rb +117 -0
  82. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  83. data/lib/sequel/plugins/validation_class_methods.rb +384 -0
  84. data/lib/sequel/plugins/validation_helpers.rb +150 -0
  85. data/lib/{sequel_core → sequel}/sql.rb +125 -190
  86. data/lib/{sequel_core → sequel}/version.rb +2 -1
  87. data/lib/sequel_core.rb +1 -172
  88. data/lib/sequel_model.rb +1 -91
  89. data/spec/adapters/firebird_spec.rb +5 -5
  90. data/spec/adapters/informix_spec.rb +1 -1
  91. data/spec/adapters/mysql_spec.rb +128 -42
  92. data/spec/adapters/oracle_spec.rb +47 -19
  93. data/spec/adapters/postgres_spec.rb +64 -52
  94. data/spec/adapters/spec_helper.rb +1 -1
  95. data/spec/adapters/sqlite_spec.rb +12 -17
  96. data/spec/{sequel_core → core}/connection_pool_spec.rb +10 -10
  97. data/spec/{sequel_core → core}/core_ext_spec.rb +19 -19
  98. data/spec/{sequel_core → core}/core_sql_spec.rb +68 -71
  99. data/spec/{sequel_core → core}/database_spec.rb +135 -99
  100. data/spec/{sequel_core → core}/dataset_spec.rb +398 -242
  101. data/spec/{sequel_core → core}/expression_filters_spec.rb +13 -13
  102. data/spec/core/migration_spec.rb +263 -0
  103. data/spec/{sequel_core → core}/object_graph_spec.rb +10 -10
  104. data/spec/{sequel_core → core}/pretty_table_spec.rb +2 -2
  105. data/spec/{sequel_core → core}/schema_generator_spec.rb +0 -0
  106. data/spec/{sequel_core → core}/schema_spec.rb +8 -10
  107. data/spec/{sequel_core → core}/spec_helper.rb +29 -2
  108. data/spec/{sequel_core → core}/version_spec.rb +0 -0
  109. data/spec/extensions/blank_spec.rb +67 -0
  110. data/spec/extensions/caching_spec.rb +201 -0
  111. data/spec/{sequel_model/hooks_spec.rb → extensions/hook_class_methods_spec.rb} +8 -23
  112. data/spec/{sequel_model → extensions}/inflector_spec.rb +3 -0
  113. data/spec/{sequel_core → extensions}/migration_spec.rb +4 -4
  114. data/spec/extensions/pagination_spec.rb +99 -0
  115. data/spec/extensions/pretty_table_spec.rb +91 -0
  116. data/spec/extensions/query_spec.rb +85 -0
  117. data/spec/{sequel_model → extensions}/schema_spec.rb +22 -1
  118. data/spec/extensions/serialization_spec.rb +109 -0
  119. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  120. data/spec/{sequel_model → extensions}/spec_helper.rb +13 -4
  121. data/spec/extensions/string_date_time_spec.rb +93 -0
  122. data/spec/{sequel_model/validations_spec.rb → extensions/validation_class_methods_spec.rb} +15 -103
  123. data/spec/extensions/validation_helpers_spec.rb +291 -0
  124. data/spec/integration/dataset_test.rb +31 -0
  125. data/spec/integration/eager_loader_test.rb +17 -30
  126. data/spec/integration/schema_test.rb +8 -5
  127. data/spec/integration/spec_helper.rb +17 -0
  128. data/spec/integration/transaction_test.rb +68 -0
  129. data/spec/{sequel_model → model}/association_reflection_spec.rb +0 -0
  130. data/spec/{sequel_model → model}/associations_spec.rb +23 -10
  131. data/spec/{sequel_model → model}/base_spec.rb +29 -20
  132. data/spec/{sequel_model → model}/caching_spec.rb +16 -14
  133. data/spec/{sequel_model → model}/dataset_methods_spec.rb +0 -0
  134. data/spec/{sequel_model → model}/eager_loading_spec.rb +8 -8
  135. data/spec/model/hooks_spec.rb +472 -0
  136. data/spec/model/inflector_spec.rb +126 -0
  137. data/spec/{sequel_model → model}/model_spec.rb +25 -20
  138. data/spec/model/plugins_spec.rb +142 -0
  139. data/spec/{sequel_model → model}/record_spec.rb +121 -62
  140. data/spec/model/schema_spec.rb +92 -0
  141. data/spec/model/spec_helper.rb +124 -0
  142. data/spec/model/validations_spec.rb +1080 -0
  143. metadata +136 -107
  144. data/lib/sequel_core/core_ext.rb +0 -217
  145. data/lib/sequel_core/dataset/callback.rb +0 -13
  146. data/lib/sequel_core/dataset/schema.rb +0 -15
  147. data/lib/sequel_core/deprecated.rb +0 -26
  148. data/lib/sequel_core/exceptions.rb +0 -44
  149. data/lib/sequel_core/schema.rb +0 -2
  150. data/lib/sequel_core/schema/sql.rb +0 -325
  151. data/lib/sequel_model/association_reflection.rb +0 -267
  152. data/lib/sequel_model/associations.rb +0 -499
  153. data/lib/sequel_model/base.rb +0 -539
  154. data/lib/sequel_model/caching.rb +0 -82
  155. data/lib/sequel_model/dataset_methods.rb +0 -26
  156. data/lib/sequel_model/eager_loading.rb +0 -370
  157. data/lib/sequel_model/hooks.rb +0 -101
  158. data/lib/sequel_model/plugins.rb +0 -62
  159. data/lib/sequel_model/record.rb +0 -568
  160. data/lib/sequel_model/schema.rb +0 -49
  161. data/lib/sequel_model/validations.rb +0 -429
  162. data/spec/sequel_model/plugins_spec.rb +0 -80
@@ -0,0 +1,92 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe Sequel::Model, "table_exists?" do
4
+
5
+ before(:each) do
6
+ MODEL_DB.reset
7
+ @model = Class.new(Sequel::Model(:items))
8
+ end
9
+
10
+ it "should get the table name and question the model's db if table_exists?" do
11
+ @model.should_receive(:table_name).and_return(:items)
12
+ @model.db.should_receive(:table_exists?)
13
+ @model.table_exists?
14
+ end
15
+
16
+ end
17
+
18
+ describe Sequel::Model, "create_table and schema" do
19
+
20
+ before(:each) do
21
+ MODEL_DB.reset
22
+ deprec do
23
+ @model = Class.new(Sequel::Model) do
24
+ set_schema(:items) do
25
+ text :name
26
+ float :price, :null => false
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ deprec_specify "should get the create table SQL list from the db and execute it line by line" do
33
+ @model.create_table
34
+ MODEL_DB.sqls.should == ['CREATE TABLE items (name text, price float NOT NULL)']
35
+ end
36
+
37
+ deprec_specify "should reload the schema from the database" do
38
+ schem = {:name=>{:type=>:string}, :price=>{:type=>:float}}
39
+ @model.db.should_receive(:schema).with(:items, :reload=>true).and_return(schem.to_a.sort_by{|x| x[0].to_s})
40
+ @model.create_table
41
+ @model.db_schema.should == schem
42
+ @model.instance_variable_get(:@columns).should == [:name, :price]
43
+ end
44
+
45
+ deprec_specify "should return the schema generator via schema" do
46
+ @model.schema.should be_a_kind_of(Sequel::Schema::Generator)
47
+ end
48
+
49
+ deprec_specify "should use the superclasses schema if it exists" do
50
+ @submodel = Class.new(@model)
51
+ @submodel.schema.should be_a_kind_of(Sequel::Schema::Generator)
52
+ end
53
+
54
+ deprec_specify "should return nil if no schema is present" do
55
+ @model = Class.new(Sequel::Model)
56
+ @model.schema.should == nil
57
+ @submodel = Class.new(@model)
58
+ @submodel.schema.should == nil
59
+ end
60
+ end
61
+
62
+ describe Sequel::Model, "drop_table" do
63
+
64
+ before(:each) do
65
+ MODEL_DB.reset
66
+ @model = Class.new(Sequel::Model(:items))
67
+ end
68
+
69
+ deprec_specify "should get the drop table SQL for the associated table and then execute the SQL." do
70
+ @model.should_receive(:table_name).and_return(:items)
71
+ @model.db.should_receive(:drop_table_sql).with(:items)
72
+ @model.db.should_receive(:execute).and_return(:true)
73
+ @model.drop_table
74
+ end
75
+
76
+ end
77
+
78
+ describe Sequel::Model, "create_table!" do
79
+
80
+ before(:each) do
81
+ MODEL_DB.reset
82
+ @model = Class.new(Sequel::Model(:items))
83
+ end
84
+
85
+ deprec_specify "should drop table if it exists and then create the table" do
86
+ @model.should_receive(:drop_table).and_return(true)
87
+ @model.should_receive(:create_table).and_return(true)
88
+
89
+ @model.create_table!
90
+ end
91
+
92
+ end
@@ -0,0 +1,124 @@
1
+ require 'rubygems'
2
+ unless Object.const_defined?('Sequel')
3
+ $:.unshift(File.join(File.dirname(__FILE__), "../../lib/"))
4
+ require 'sequel/core'
5
+ end
6
+ unless Sequel.const_defined?('Model')
7
+ $:.unshift(File.join(File.dirname(__FILE__), "../../lib/"))
8
+ require 'sequel/model'
9
+ end
10
+
11
+ Sequel.virtual_row_instance_eval = true
12
+
13
+ module Spec::Example::ExampleMethods
14
+ def deprec
15
+ output = Sequel::Deprecation.output = nil
16
+ begin
17
+ yield
18
+ ensure
19
+ Sequel::Deprecation.output = output
20
+ end
21
+ end
22
+ end
23
+
24
+ module Spec::Example::ExampleGroupMethods
25
+ def deprec_specify(*args, &block)
26
+ specify(*args) do
27
+ output = Sequel::Deprecation.output
28
+ Sequel::Deprecation.output = nil
29
+ begin
30
+ instance_eval(&block)
31
+ ensure
32
+ Sequel::Deprecation.output = output
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ class MockDataset < Sequel::Dataset
39
+ def insert(*args)
40
+ @db.execute insert_sql(*args)
41
+ end
42
+
43
+ def update(*args)
44
+ @db.execute update_sql(*args)
45
+ end
46
+
47
+ def delete(*args)
48
+ @db.execute delete_sql(*args)
49
+ end
50
+
51
+ def fetch_rows(sql)
52
+ return if sql =~ /information_schema/
53
+ @db.execute(sql)
54
+ yield({:id => 1, :x => 1})
55
+ end
56
+
57
+ def quoted_identifier(c)
58
+ "\"#{c}\""
59
+ end
60
+ end
61
+
62
+ class MockDatabase < Sequel::Database
63
+ @@quote_identifiers = false
64
+ self.identifier_input_method = nil
65
+ self.identifier_output_method = nil
66
+ attr_reader :sqls
67
+
68
+ def execute(sql, opts={})
69
+ @sqls ||= []
70
+ @sqls << sql
71
+ end
72
+
73
+ def reset
74
+ @sqls = []
75
+ end
76
+
77
+ def schema(table_name, opts)
78
+ if table_name
79
+ [[:id, {:primary_key=>true}]]
80
+ else
81
+ {table_name=>[[:id, {:primary_key=>true}]]}
82
+ end
83
+ end
84
+
85
+ def transaction(opts={})
86
+ return yield if @transactions.include?(Thread.current)
87
+ execute('BEGIN')
88
+ begin
89
+ @transactions << Thread.current
90
+ yield
91
+ rescue Exception => e
92
+ execute('ROLLBACK')
93
+ transaction_error(e)
94
+ ensure
95
+ unless e
96
+ execute('COMMIT')
97
+ end
98
+ @transactions.delete(Thread.current)
99
+ end
100
+ end
101
+
102
+ def dataset(opts=nil); MockDataset.new(self, opts); end
103
+ end
104
+
105
+ class << Sequel::Model
106
+ alias orig_columns columns
107
+ alias orig_str_columns str_columns
108
+ def columns(*cols)
109
+ return if cols.empty?
110
+ define_method(:columns){cols}
111
+ @dataset.instance_variable_set(:@columns, cols) if @dataset
112
+ define_method(:str_columns){cols.map{|x|x.to_s.freeze}}
113
+ def_column_accessor(*cols)
114
+ @columns = cols
115
+ @db_schema = {}
116
+ cols.each{|c| @db_schema[c] = {}}
117
+ end
118
+ def simple_table
119
+ nil
120
+ end
121
+ end
122
+
123
+ Sequel::Model.use_transactions = false
124
+ Sequel::Model.db = MODEL_DB = MockDatabase.new
@@ -0,0 +1,1080 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe Sequel::Model::Errors do
4
+ before do
5
+ @errors = Sequel::Model::Errors.new
6
+ end
7
+
8
+ specify "should be clearable using #clear" do
9
+ @errors.add(:a, 'b')
10
+ @errors.should == {:a=>['b']}
11
+ @errors.clear
12
+ @errors.should == {}
13
+ end
14
+
15
+ specify "should be empty if no errors are added" do
16
+ @errors.should be_empty
17
+ @errors[:blah] << "blah"
18
+ @errors.should_not be_empty
19
+ end
20
+
21
+ specify "should return errors for a specific attribute using #on or #[]" do
22
+ @errors[:blah].should == []
23
+ @errors.on(:blah).should == []
24
+
25
+ @errors[:blah] << 'blah'
26
+ @errors[:blah].should == ['blah']
27
+ @errors.on(:blah).should == ['blah']
28
+
29
+ @errors[:bleu].should == []
30
+ @errors.on(:bleu).should == []
31
+ end
32
+
33
+ specify "should accept errors using #[] << or #add" do
34
+ @errors[:blah] << 'blah'
35
+ @errors[:blah].should == ['blah']
36
+
37
+ @errors.add :blah, 'zzzz'
38
+ @errors[:blah].should == ['blah', 'zzzz']
39
+ end
40
+
41
+ specify "should return full messages using #full_messages" do
42
+ @errors.full_messages.should == []
43
+
44
+ @errors[:blow] << 'blieuh'
45
+ @errors[:blow] << 'blich'
46
+ @errors[:blay] << 'bliu'
47
+ msgs = @errors.full_messages
48
+ msgs.size.should == 3
49
+ msgs.should include('blow blieuh', 'blow blich', 'blay bliu')
50
+ end
51
+
52
+ specify "should return the number of error messages using #count" do
53
+ @errors.count.should == 0
54
+ @errors.add(:a, 'b')
55
+ @errors.count.should == 1
56
+ @errors.add(:a, 'c')
57
+ @errors.count.should == 2
58
+ @errors.add(:b, 'c')
59
+ @errors.count.should == 3
60
+ end
61
+
62
+ specify "should return the array of error messages for a given attribute using #on" do
63
+ @errors.add(:a, 'b')
64
+ @errors.on(:a).should == ['b']
65
+ @errors.add(:a, 'c')
66
+ @errors.on(:a).should == ['b', 'c']
67
+ @errors.add(:b, 'c')
68
+ @errors.on(:a).should == ['b', 'c']
69
+ end
70
+
71
+ specify "should return nil if there are no error messages for a given attribute using #on" do
72
+ @errors.on(:a).should == nil
73
+ @errors.add(:b, 'b')
74
+ @errors.on(:a).should == nil
75
+ end
76
+ end
77
+
78
+ describe Sequel::Model do
79
+ before do
80
+ deprec do
81
+ @c = Class.new(Sequel::Model) do
82
+ def self.validates_coolness_of(attr)
83
+ validates_each(attr) {|o, a, v| o.errors[a] << 'is not cool' if v != :cool}
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ deprec_specify "should respond to validates, validations, has_validations?" do
90
+ @c.should respond_to(:validations)
91
+ @c.should respond_to(:has_validations?)
92
+ end
93
+
94
+ deprec_specify "should acccept validation definitions using validates_each" do
95
+ @c.validates_each(:xx, :yy) {|o, a, v| o.errors[a] << 'too low' if v < 50}
96
+ o = @c.new
97
+ o.should_receive(:xx).once.and_return(40)
98
+ o.should_receive(:yy).once.and_return(60)
99
+ o.valid?.should == false
100
+ o.errors.full_messages.should == ['xx too low']
101
+ end
102
+
103
+ deprec_specify "should return true/false for has_validations?" do
104
+ @c.has_validations?.should == false
105
+ @c.validates_each(:xx) {1}
106
+ @c.has_validations?.should == true
107
+ end
108
+
109
+ deprec_specify "should validate multiple attributes at once" do
110
+ o = @c.new
111
+ def o.xx
112
+ 1
113
+ end
114
+ def o.yy
115
+ 2
116
+ end
117
+ vals = nil
118
+ atts = nil
119
+ @c.validates_each([:xx, :yy]){|obj,a,v| atts=a; vals=v}
120
+ o.valid?
121
+ vals.should == [1,2]
122
+ atts.should == [:xx, :yy]
123
+ end
124
+
125
+ deprec_specify "should respect allow_missing option when using multiple attributes" do
126
+ o = @c.new
127
+ def o.xx
128
+ self[:xx]
129
+ end
130
+ def o.yy
131
+ self[:yy]
132
+ end
133
+ vals = nil
134
+ atts = nil
135
+ @c.validates_each([:xx, :yy], :allow_missing=>true){|obj,a,v| atts=a; vals=v}
136
+
137
+ o.values[:xx] = 1
138
+ o.valid?
139
+ vals.should == [1,nil]
140
+ atts.should == [:xx, :yy]
141
+
142
+ vals = nil
143
+ atts = nil
144
+ o.values.clear
145
+ o.values[:yy] = 2
146
+ o.valid?
147
+ vals.should == [nil, 2]
148
+ atts.should == [:xx, :yy]
149
+
150
+ vals = nil
151
+ atts = nil
152
+ o.values.clear
153
+ o.valid?.should == true
154
+ vals.should == nil
155
+ atts.should == nil
156
+ end
157
+
158
+ deprec_specify "should overwrite existing validation with the same tag and attribute" do
159
+ @c.validates_each(:xx, :xx, :tag=>:low) {|o, a, v| o.xxx; o.errors[a] << 'too low' if v < 50}
160
+ @c.validates_each(:yy, :yy) {|o, a, v| o.yyy; o.errors[a] << 'too low' if v < 50}
161
+ @c.validates_presence_of(:zz, :zz)
162
+ @c.validates_length_of(:aa, :aa, :tag=>:blah)
163
+ o = @c.new
164
+ def o.zz
165
+ @a ||= 0
166
+ @a += 1
167
+ end
168
+ def o.aa
169
+ @b ||= 0
170
+ @b += 1
171
+ end
172
+ o.should_receive(:xx).once.and_return(40)
173
+ o.should_receive(:yy).once.and_return(60)
174
+ o.should_receive(:xxx).once
175
+ o.should_receive(:yyy).twice
176
+ o.valid?.should == false
177
+ o.zz.should == 2
178
+ o.aa.should == 2
179
+ o.errors.full_messages.should == ['xx too low']
180
+ end
181
+
182
+ deprec_specify "should provide a validates method that takes block with validation definitions" do
183
+ @c.validates do
184
+ coolness_of :blah
185
+ end
186
+ @c.validations[:blah].should_not be_empty
187
+ o = @c.new
188
+ o.should_receive(:blah).once.and_return(nil)
189
+ o.valid?.should == false
190
+ o.errors.full_messages.should == ['blah is not cool']
191
+ end
192
+ end
193
+
194
+ describe Sequel::Model do
195
+ before do
196
+ @c = Class.new(Sequel::Model) do
197
+ columns :score
198
+ def validate
199
+ errors[:score] << 'too low' if score < 87
200
+ end
201
+ end
202
+
203
+ @o = @c.new
204
+ end
205
+
206
+ specify "should supply a #valid? method that returns true if validations pass" do
207
+ @o.score = 50
208
+ @o.should_not be_valid
209
+ @o.score = 100
210
+ @o.should be_valid
211
+ end
212
+
213
+ specify "should provide an errors object" do
214
+ @o.score = 100
215
+ @o.should be_valid
216
+ @o.errors.should be_empty
217
+
218
+ @o.score = 86
219
+ @o.should_not be_valid
220
+ @o.errors[:score].should == ['too low']
221
+ @o.errors[:blah].should be_empty
222
+ end
223
+ end
224
+
225
+ describe 'Sequel::Model::Validation::Generator' do
226
+ before do
227
+ $testit = nil
228
+
229
+ @c = Class.new(Sequel::Model) do
230
+ def self.validates_blah
231
+ $testit = 1324
232
+ end
233
+ end
234
+ end
235
+
236
+ deprec_specify "should instance_eval the block, sending everything to its receiver" do
237
+ @c.class_eval do
238
+ validates do
239
+ blah
240
+ end
241
+ end
242
+ $testit.should == 1324
243
+ end
244
+ end
245
+
246
+ describe Sequel::Model do
247
+ before do
248
+ @c = Class.new(Sequel::Model) do
249
+ columns :value
250
+
251
+ def self.filter(*args)
252
+ o = Object.new
253
+ def o.count; 2; end
254
+ o
255
+ end
256
+
257
+ def skip; false; end
258
+ def dont_skip; true; end
259
+ end
260
+ @m = @c.new
261
+ end
262
+
263
+ deprec_specify "should validate acceptance_of" do
264
+ @c.validates_acceptance_of :value
265
+ @m.should be_valid
266
+ @m.value = '1'
267
+ @m.should be_valid
268
+ end
269
+
270
+ deprec_specify "should validate acceptance_of with accept" do
271
+ @c.validates_acceptance_of :value, :accept => 'true'
272
+ @m.value = '1'
273
+ @m.should_not be_valid
274
+ @m.value = 'true'
275
+ @m.should be_valid
276
+ end
277
+
278
+ deprec_specify "should validate acceptance_of with allow_nil => false" do
279
+ @c.validates_acceptance_of :value, :allow_nil => false
280
+ @m.should_not be_valid
281
+ end
282
+
283
+ deprec_specify "should validate acceptance_of with allow_missing => true" do
284
+ @c.validates_acceptance_of :value, :allow_missing => true
285
+ @m.should be_valid
286
+ end
287
+
288
+ deprec_specify "should validate acceptance_of with allow_missing => true and allow_nil => false" do
289
+ @c.validates_acceptance_of :value, :allow_missing => true, :allow_nil => false
290
+ @m.should be_valid
291
+ @m.value = nil
292
+ @m.should_not be_valid
293
+ end
294
+
295
+ deprec_specify "should validate acceptance_of with if => true" do
296
+ @c.validates_acceptance_of :value, :if => :dont_skip
297
+ @m.value = '0'
298
+ @m.should_not be_valid
299
+ end
300
+
301
+ deprec_specify "should validate acceptance_of with if => false" do
302
+ @c.validates_acceptance_of :value, :if => :skip
303
+ @m.value = '0'
304
+ @m.should be_valid
305
+ end
306
+
307
+ deprec_specify "should validate acceptance_of with if proc that evaluates to true" do
308
+ @c.validates_acceptance_of :value, :if => proc{true}
309
+ @m.value = '0'
310
+ @m.should_not be_valid
311
+ end
312
+
313
+ deprec_specify "should validate acceptance_of with if proc that evaluates to false" do
314
+ @c.validates_acceptance_of :value, :if => proc{false}
315
+ @m.value = '0'
316
+ @m.should be_valid
317
+ end
318
+
319
+ deprec_specify "should raise an error if :if option is not a Symbol, Proc, or nil" do
320
+ @c.validates_acceptance_of :value, :if => 1
321
+ @m.value = '0'
322
+ proc{@m.valid?}.should raise_error(Sequel::Error)
323
+ end
324
+
325
+ deprec_specify "should validate confirmation_of" do
326
+ @c.send(:attr_accessor, :value_confirmation)
327
+ @c.validates_confirmation_of :value
328
+
329
+ @m.value = 'blah'
330
+ @m.should_not be_valid
331
+
332
+ @m.value_confirmation = 'blah'
333
+ @m.should be_valid
334
+ end
335
+
336
+ deprec_specify "should validate confirmation_of with if => true" do
337
+ @c.send(:attr_accessor, :value_confirmation)
338
+ @c.validates_confirmation_of :value, :if => :dont_skip
339
+
340
+ @m.value = 'blah'
341
+ @m.should_not be_valid
342
+ end
343
+
344
+ deprec_specify "should validate confirmation_of with if => false" do
345
+ @c.send(:attr_accessor, :value_confirmation)
346
+ @c.validates_confirmation_of :value, :if => :skip
347
+
348
+ @m.value = 'blah'
349
+ @m.should be_valid
350
+ end
351
+
352
+ deprec_specify "should validate confirmation_of with allow_missing => true" do
353
+ @c.send(:attr_accessor, :value_confirmation)
354
+ @c.validates_acceptance_of :value, :allow_missing => true
355
+ @m.should be_valid
356
+ @m.value_confirmation = 'blah'
357
+ @m.should be_valid
358
+ @m.value = nil
359
+ @m.should_not be_valid
360
+ end
361
+
362
+ deprec_specify "should validate format_of" do
363
+ @c.validates_format_of :value, :with => /.+_.+/
364
+ @m.value = 'abc_'
365
+ @m.should_not be_valid
366
+ @m.value = 'abc_def'
367
+ @m.should be_valid
368
+ end
369
+
370
+ deprec_specify "should raise for validate_format_of without regexp" do
371
+ proc {@c.validates_format_of :value}.should raise_error(ArgumentError)
372
+ proc {@c.validates_format_of :value, :with => :blah}.should raise_error(ArgumentError)
373
+ end
374
+
375
+ deprec_specify "should validate format_of with if => true" do
376
+ @c.validates_format_of :value, :with => /_/, :if => :dont_skip
377
+
378
+ @m.value = 'a'
379
+ @m.should_not be_valid
380
+ end
381
+
382
+ deprec_specify "should validate format_of with if => false" do
383
+ @c.validates_format_of :value, :with => /_/, :if => :skip
384
+
385
+ @m.value = 'a'
386
+ @m.should be_valid
387
+ end
388
+
389
+ deprec_specify "should validate format_of with allow_missing => true" do
390
+ @c.validates_format_of :value, :allow_missing => true, :with=>/./
391
+ @m.should be_valid
392
+ @m.value = nil
393
+ @m.should_not be_valid
394
+ end
395
+
396
+ deprec_specify "should validate length_of with maximum" do
397
+ @c.validates_length_of :value, :maximum => 5
398
+ @m.should_not be_valid
399
+ @m.value = '12345'
400
+ @m.should be_valid
401
+ @m.value = '123456'
402
+ @m.should_not be_valid
403
+ end
404
+
405
+ deprec_specify "should validate length_of with minimum" do
406
+ @c.validates_length_of :value, :minimum => 5
407
+ @m.should_not be_valid
408
+ @m.value = '12345'
409
+ @m.should be_valid
410
+ @m.value = '1234'
411
+ @m.should_not be_valid
412
+ end
413
+
414
+ deprec_specify "should validate length_of with within" do
415
+ @c.validates_length_of :value, :within => 2..5
416
+ @m.should_not be_valid
417
+ @m.value = '12345'
418
+ @m.should be_valid
419
+ @m.value = '1'
420
+ @m.should_not be_valid
421
+ @m.value = '123456'
422
+ @m.should_not be_valid
423
+ end
424
+
425
+ deprec_specify "should validate length_of with is" do
426
+ @c.validates_length_of :value, :is => 3
427
+ @m.should_not be_valid
428
+ @m.value = '123'
429
+ @m.should be_valid
430
+ @m.value = '12'
431
+ @m.should_not be_valid
432
+ @m.value = '1234'
433
+ @m.should_not be_valid
434
+ end
435
+
436
+ deprec_specify "should validate length_of with allow_nil" do
437
+ @c.validates_length_of :value, :is => 3, :allow_nil => true
438
+ @m.should be_valid
439
+ end
440
+
441
+ deprec_specify "should validate length_of with if => true" do
442
+ @c.validates_length_of :value, :is => 3, :if => :dont_skip
443
+
444
+ @m.value = 'a'
445
+ @m.should_not be_valid
446
+ end
447
+
448
+ deprec_specify "should validate length_of with if => false" do
449
+ @c.validates_length_of :value, :is => 3, :if => :skip
450
+
451
+ @m.value = 'a'
452
+ @m.should be_valid
453
+ end
454
+
455
+ deprec_specify "should validate length_of with allow_missing => true" do
456
+ @c.validates_length_of :value, :allow_missing => true, :minimum => 5
457
+ @m.should be_valid
458
+ @m.value = nil
459
+ @m.should_not be_valid
460
+ end
461
+
462
+ deprec_specify "should allow multiple calls to validates_length_of with different options without overwriting" do
463
+ @c.validates_length_of :value, :maximum => 5
464
+ @c.validates_length_of :value, :minimum => 5
465
+ @m.should_not be_valid
466
+ @m.value = '12345'
467
+ @m.should be_valid
468
+ @m.value = '123456'
469
+ @m.should_not be_valid
470
+ @m.value = '12345'
471
+ @m.should be_valid
472
+ @m.value = '1234'
473
+ @m.should_not be_valid
474
+ end
475
+
476
+ deprec_specify "should validate numericality_of" do
477
+ @c.validates_numericality_of :value
478
+ @m.value = 'blah'
479
+ @m.should_not be_valid
480
+ @m.value = '123'
481
+ @m.should be_valid
482
+ @m.value = '123.1231'
483
+ @m.should be_valid
484
+ @m.value = '+1'
485
+ @m.should be_valid
486
+ @m.value = '-1'
487
+ @m.should be_valid
488
+ @m.value = '+1.123'
489
+ @m.should be_valid
490
+ @m.value = '-0.123'
491
+ @m.should be_valid
492
+ @m.value = '-0.123E10'
493
+ @m.should be_valid
494
+ @m.value = '32.123e10'
495
+ @m.should be_valid
496
+ @m.value = '+32.123E10'
497
+ @m.should be_valid
498
+ @m.should be_valid
499
+ @m.value = '.0123'
500
+ end
501
+
502
+ deprec_specify "should validate numericality_of with only_integer" do
503
+ @c.validates_numericality_of :value, :only_integer => true
504
+ @m.value = 'blah'
505
+ @m.should_not be_valid
506
+ @m.value = '123'
507
+ @m.should be_valid
508
+ @m.value = '123.1231'
509
+ @m.should_not be_valid
510
+ end
511
+
512
+ deprec_specify "should validate numericality_of with if => true" do
513
+ @c.validates_numericality_of :value, :if => :dont_skip
514
+
515
+ @m.value = 'a'
516
+ @m.should_not be_valid
517
+ end
518
+
519
+ deprec_specify "should validate numericality_of with if => false" do
520
+ @c.validates_numericality_of :value, :if => :skip
521
+
522
+ @m.value = 'a'
523
+ @m.should be_valid
524
+ end
525
+
526
+ deprec_specify "should validate numericality_of with allow_missing => true" do
527
+ @c.validates_numericality_of :value, :allow_missing => true
528
+ @m.should be_valid
529
+ @m.value = nil
530
+ @m.should_not be_valid
531
+ end
532
+
533
+ deprec_specify "should validate presence_of" do
534
+ @c.validates_presence_of :value
535
+ @m.should_not be_valid
536
+ @m.value = ''
537
+ @m.should_not be_valid
538
+ @m.value = 1234
539
+ @m.should be_valid
540
+ @m.value = nil
541
+ @m.should_not be_valid
542
+ @m.value = true
543
+ @m.should be_valid
544
+ @m.value = false
545
+ @m.should be_valid
546
+ end
547
+
548
+ deprec_specify "should validate inclusion_of with an array" do
549
+ @c.validates_inclusion_of :value, :in => [1,2]
550
+ @m.should_not be_valid
551
+ @m.value = 1
552
+ @m.should be_valid
553
+ @m.value = 1.5
554
+ @m.should_not be_valid
555
+ @m.value = 2
556
+ @m.should be_valid
557
+ @m.value = 3
558
+ @m.should_not be_valid
559
+ end
560
+
561
+ deprec_specify "should validate inclusion_of with a range" do
562
+ @c.validates_inclusion_of :value, :in => 1..4
563
+ @m.should_not be_valid
564
+ @m.value = 1
565
+ @m.should be_valid
566
+ @m.value = 1.5
567
+ @m.should be_valid
568
+ @m.value = 0
569
+ @m.should_not be_valid
570
+ @m.value = 5
571
+ @m.should_not be_valid
572
+ end
573
+
574
+ deprec_specify "should raise an error if inclusion_of doesn't receive a valid :in option" do
575
+ lambda {
576
+ @c.validates_inclusion_of :value
577
+ }.should raise_error(ArgumentError)
578
+
579
+ lambda {
580
+ @c.validates_inclusion_of :value, :in => 1
581
+ }.should raise_error(ArgumentError)
582
+ end
583
+
584
+ deprec_specify "should raise an error if inclusion_of handles :allow_nil too" do
585
+ @c.validates_inclusion_of :value, :in => 1..4, :allow_nil => true
586
+ @m.value = nil
587
+ @m.should be_valid
588
+ @m.value = 0
589
+ @m.should_not be_valid
590
+ end
591
+
592
+ deprec_specify "should validate presence_of with if => true" do
593
+ @c.validates_presence_of :value, :if => :dont_skip
594
+ @m.should_not be_valid
595
+ end
596
+
597
+ deprec_specify "should validate presence_of with if => false" do
598
+ @c.validates_presence_of :value, :if => :skip
599
+ @m.should be_valid
600
+ end
601
+
602
+ deprec_specify "should validate presence_of with allow_missing => true" do
603
+ @c.validates_presence_of :value, :allow_missing => true
604
+ @m.should be_valid
605
+ @m.value = nil
606
+ @m.should_not be_valid
607
+ end
608
+
609
+ deprec_specify "should validate uniqueness_of with if => true" do
610
+ @c.validates_uniqueness_of :value, :if => :dont_skip
611
+
612
+ @m.value = 'a'
613
+ @m.should_not be_valid
614
+ end
615
+
616
+ deprec_specify "should validate uniqueness_of with if => false" do
617
+ @c.validates_uniqueness_of :value, :if => :skip
618
+
619
+ @m.value = 'a'
620
+ @m.should be_valid
621
+ end
622
+
623
+ deprec_specify "should validate uniqueness_of with allow_missing => true" do
624
+ @c.validates_uniqueness_of :value, :allow_missing => true
625
+ @m.should be_valid
626
+ @m.value = nil
627
+ @m.should_not be_valid
628
+ end
629
+ end
630
+
631
+ context "Superclass validations" do
632
+ before do
633
+ deprec do
634
+ @c1 = Class.new(Sequel::Model) do
635
+ columns :value
636
+ validates_length_of :value, :minimum => 5
637
+ end
638
+
639
+ @c2 = Class.new(@c1) do
640
+ columns :value
641
+ validates_format_of :value, :with => /^[a-z]+$/
642
+ end
643
+ end
644
+ end
645
+
646
+ deprec_specify "should be checked when validating" do
647
+ o = @c2.new
648
+ o.value = 'ab'
649
+ o.valid?.should == false
650
+ o.errors.full_messages.should == [
651
+ 'value is too short'
652
+ ]
653
+
654
+ o.value = '12'
655
+ o.valid?.should == false
656
+ o.errors.full_messages.should == [
657
+ 'value is too short',
658
+ 'value is invalid'
659
+ ]
660
+
661
+ o.value = 'abcde'
662
+ o.valid?.should be_true
663
+ end
664
+
665
+ deprec_specify "should be skipped if skip_superclass_validations is called" do
666
+ @c2.skip_superclass_validations
667
+
668
+ o = @c2.new
669
+ o.value = 'ab'
670
+ o.valid?.should be_true
671
+
672
+ o.value = '12'
673
+ o.valid?.should == false
674
+ o.errors.full_messages.should == [
675
+ 'value is invalid'
676
+ ]
677
+
678
+ o.value = 'abcde'
679
+ o.valid?.should be_true
680
+ end
681
+ end
682
+
683
+ context ".validates with block" do
684
+ deprec_specify "should support calling .each" do
685
+ @c = Class.new(Sequel::Model) do
686
+ columns :vvv
687
+ validates do
688
+ each :vvv do |o, a, v|
689
+ o.errors[a] << "is less than zero" if v.to_i < 0
690
+ end
691
+ end
692
+ end
693
+
694
+ o = @c.new
695
+ o.vvv = 1
696
+ o.should be_valid
697
+ o.vvv = -1
698
+ o.should_not be_valid
699
+ end
700
+ end
701
+
702
+ describe Sequel::Model, "Validations" do
703
+
704
+ before(:all) do
705
+ class ::Person < Sequel::Model
706
+ columns :id,:name,:first_name,:last_name,:middle_name,:initials,:age, :terms
707
+ end
708
+
709
+ class ::Smurf < Person
710
+ end
711
+
712
+ class ::Cow < Sequel::Model
713
+ columns :id, :name, :got_milk
714
+ end
715
+
716
+ class ::User < Sequel::Model
717
+ columns :id, :username, :password
718
+ end
719
+
720
+ class ::Address < Sequel::Model
721
+ columns :id, :zip_code
722
+ end
723
+ end
724
+
725
+ deprec_specify "should validate the acceptance of a column" do
726
+ class ::Cow < Sequel::Model
727
+ validations.clear
728
+ validates_acceptance_of :got_milk, :accept => 'blah', :allow_nil => false
729
+ end
730
+
731
+ @cow = Cow.new
732
+ @cow.should_not be_valid
733
+ @cow.errors.full_messages.should == ["got_milk is not accepted"]
734
+
735
+ @cow.got_milk = "blah"
736
+ @cow.should be_valid
737
+ end
738
+
739
+ deprec_specify "should validate the confirmation of a column" do
740
+ class ::User < Sequel::Model
741
+ def password_confirmation
742
+ "test"
743
+ end
744
+
745
+ validations.clear
746
+ validates_confirmation_of :password
747
+ end
748
+
749
+ @user = User.new
750
+ @user.should_not be_valid
751
+ @user.errors.full_messages.should == ["password is not confirmed"]
752
+
753
+ @user.password = "test"
754
+ @user.should be_valid
755
+ end
756
+
757
+ deprec_specify "should validate format of column" do
758
+ class ::Person < Sequel::Model
759
+ validates_format_of :first_name, :with => /^[a-zA-Z]+$/
760
+ end
761
+
762
+ @person = Person.new :first_name => "Lancelot99"
763
+ @person.valid?.should be_false
764
+ @person = Person.new :first_name => "Anita"
765
+ @person.valid?.should be_true
766
+ end
767
+
768
+ deprec_specify "should validate length of column" do
769
+ class ::Person < Sequel::Model
770
+ validations.clear
771
+ validates_length_of :first_name, :maximum => 30
772
+ validates_length_of :last_name, :minimum => 30
773
+ validates_length_of :middle_name, :within => 1..5
774
+ validates_length_of :initials, :is => 2
775
+ end
776
+
777
+ @person = Person.new(
778
+ :first_name => "Anamethatiswaytofreakinglongandwayoverthirtycharacters",
779
+ :last_name => "Alastnameunderthirtychars",
780
+ :initials => "LGC",
781
+ :middle_name => "danger"
782
+ )
783
+
784
+ @person.should_not be_valid
785
+ @person.errors.full_messages.size.should == 4
786
+ @person.errors.full_messages.should include(
787
+ 'first_name is too long',
788
+ 'last_name is too short',
789
+ 'middle_name is the wrong length',
790
+ 'initials is the wrong length'
791
+ )
792
+
793
+ @person.first_name = "Lancelot"
794
+ @person.last_name = "1234567890123456789012345678901"
795
+ @person.initials = "LC"
796
+ @person.middle_name = "Will"
797
+ @person.should be_valid
798
+ end
799
+
800
+ deprec_specify "should validate that a column doesn't have a string value" do
801
+ p = Class.new(Sequel::Model)
802
+ p.class_eval do
803
+ columns :age, :price, :confirmed
804
+ self.raise_on_typecast_failure = false
805
+ validates_not_string :age
806
+ validates_not_string :confirmed
807
+ validates_not_string :price, :message=>'is not valid'
808
+ @db_schema = {:age=>{:type=>:integer}}
809
+ end
810
+
811
+ @person = p.new
812
+ @person.should be_valid
813
+
814
+ @person.confirmed = 't'
815
+ @person.should_not be_valid
816
+ @person.errors.full_messages.should == ['confirmed is a string']
817
+ @person.confirmed = true
818
+ @person.should be_valid
819
+
820
+ @person.age = 'a'
821
+ @person.should_not be_valid
822
+ @person.errors.full_messages.should == ['age is not a valid integer']
823
+ @person.db_schema[:age][:type] = :datetime
824
+ @person.should_not be_valid
825
+ @person.errors.full_messages.should == ['age is not a valid datetime']
826
+ @person.age = 20
827
+ @person.should be_valid
828
+
829
+ @person.price = 'a'
830
+ @person.should_not be_valid
831
+ @person.errors.full_messages.should == ['price is not valid']
832
+ @person.price = 20
833
+ @person.should be_valid
834
+ end
835
+
836
+ deprec_specify "should validate numericality of column" do
837
+ class ::Person < Sequel::Model
838
+ validations.clear
839
+ validates_numericality_of :age
840
+ end
841
+
842
+ @person = Person.new :age => "Twenty"
843
+ @person.should_not be_valid
844
+ @person.errors.full_messages.should == ['age is not a number']
845
+
846
+ @person.age = 20
847
+ @person.should be_valid
848
+ end
849
+
850
+ deprec_specify "should validate the presence of a column" do
851
+ class ::Cow < Sequel::Model
852
+ validations.clear
853
+ validates_presence_of :name
854
+ end
855
+
856
+ @cow = Cow.new
857
+ @cow.should_not be_valid
858
+ @cow.errors.full_messages.should == ['name is not present']
859
+
860
+ @cow.name = "Betsy"
861
+ @cow.should be_valid
862
+ end
863
+
864
+ deprec_specify "should validate the uniqueness of a column" do
865
+ class ::User < Sequel::Model
866
+ validations.clear
867
+ validates do
868
+ uniqueness_of :username
869
+ end
870
+ end
871
+ User.dataset.extend(Module.new {
872
+ def fetch_rows(sql)
873
+ @db << sql
874
+
875
+ case sql
876
+ when /COUNT.*username = '0records'/
877
+ yield({:v => 0})
878
+ when /COUNT.*username = '2records'/
879
+ yield({:v => 2})
880
+ when /COUNT.*username = '1record'/
881
+ yield({:v => 1})
882
+ when /username = '1record'/
883
+ yield({:id => 3, :username => "1record", :password => "test"})
884
+ end
885
+ end
886
+ })
887
+
888
+ @user = User.new(:username => "2records", :password => "anothertest")
889
+ @user.should_not be_valid
890
+ @user.errors.full_messages.should == ['username is already taken']
891
+
892
+ @user = User.new(:username => "1record", :password => "anothertest")
893
+ @user.should_not be_valid
894
+ @user.errors.full_messages.should == ['username is already taken']
895
+
896
+ @user = User.load(:id=>4, :username => "1record", :password => "anothertest")
897
+ @user.should_not be_valid
898
+ @user.errors.full_messages.should == ['username is already taken']
899
+
900
+ @user = User.load(:id=>3, :username => "1record", :password => "anothertest")
901
+ @user.should be_valid
902
+ @user.errors.full_messages.should == []
903
+
904
+ @user = User.new(:username => "0records", :password => "anothertest")
905
+ @user.should be_valid
906
+ @user.errors.full_messages.should == []
907
+ end
908
+
909
+ deprec_specify "should validate the uniqueness of multiple columns" do
910
+ class ::User < Sequel::Model
911
+ validations.clear
912
+ validates do
913
+ uniqueness_of [:username, :password]
914
+ end
915
+ end
916
+ User.dataset.extend(Module.new {
917
+ def fetch_rows(sql)
918
+ @db << sql
919
+
920
+ case sql
921
+ when /COUNT.*username = '0records'/
922
+ yield({:v => 0})
923
+ when /COUNT.*username = '2records'/
924
+ yield({:v => 2})
925
+ when /COUNT.*username = '1record'/
926
+ yield({:v => 1})
927
+ when /username = '1record'/
928
+ if sql =~ /password = 'anothertest'/
929
+ yield({:id => 3, :username => "1record", :password => "anothertest"})
930
+ else
931
+ yield({:id => 4, :username => "1record", :password => "test"})
932
+ end
933
+ end
934
+ end
935
+ })
936
+
937
+ @user = User.new(:username => "2records", :password => "anothertest")
938
+ @user.should_not be_valid
939
+ @user.errors.full_messages.should == ['username and password is already taken']
940
+
941
+ @user = User.new(:username => "1record", :password => "anothertest")
942
+ @user.should_not be_valid
943
+ @user.errors.full_messages.should == ['username and password is already taken']
944
+
945
+ @user = User.load(:id=>4, :username => "1record", :password => "anothertest")
946
+ @user.should_not be_valid
947
+ @user.errors.full_messages.should == ['username and password is already taken']
948
+
949
+ @user = User.load(:id=>3, :username => "1record", :password => "test")
950
+ @user.should_not be_valid
951
+ @user.errors.full_messages.should == ['username and password is already taken']
952
+
953
+ @user = User.load(:id=>3, :username => "1record", :password => "anothertest")
954
+ @user.should be_valid
955
+ @user.errors.full_messages.should == []
956
+
957
+ @user = User.new(:username => "0records", :password => "anothertest")
958
+ @user.should be_valid
959
+ @user.errors.full_messages.should == []
960
+ end
961
+
962
+ deprec_specify "should have a validates block that contains multiple validations" do
963
+ class ::Person < Sequel::Model
964
+ validations.clear
965
+ validates do
966
+ format_of :first_name, :with => /^[a-zA-Z]+$/
967
+ length_of :first_name, :maximum => 30
968
+ end
969
+ end
970
+
971
+ Person.validations[:first_name].size.should == 2
972
+
973
+ @person = Person.new :first_name => "Lancelot99"
974
+ @person.valid?.should be_false
975
+
976
+ @person2 = Person.new :first_name => "Wayne"
977
+ @person2.valid?.should be_true
978
+ end
979
+
980
+ deprec_specify "should allow 'longhand' validations direcly within the model." do
981
+ lambda {
982
+ class ::Person < Sequel::Model
983
+ validations.clear
984
+ validates_length_of :first_name, :maximum => 30
985
+ end
986
+ }.should_not raise_error
987
+ Person.validations.length.should eql(1)
988
+ end
989
+
990
+ deprec_specify "should define a has_validations? method which returns true if the model has validations, false otherwise" do
991
+ class ::Person < Sequel::Model
992
+ validations.clear
993
+ validates do
994
+ format_of :first_name, :with => /\w+/
995
+ length_of :first_name, :maximum => 30
996
+ end
997
+ end
998
+
999
+ class ::Smurf < Person
1000
+ validations.clear
1001
+ end
1002
+
1003
+ Person.should have_validations
1004
+ Smurf.should_not have_validations
1005
+ end
1006
+
1007
+ deprec_specify "should validate correctly instances initialized with string keys" do
1008
+ class ::Can < Sequel::Model
1009
+ columns :id, :name
1010
+
1011
+ validates_length_of :name, :minimum => 4
1012
+ end
1013
+
1014
+ Can.new('name' => 'ab').should_not be_valid
1015
+ Can.new('name' => 'abcd').should be_valid
1016
+ end
1017
+
1018
+ end
1019
+
1020
+ describe "Model#save!" do
1021
+ before do
1022
+ @c = Class.new(Sequel::Model(:people)) do
1023
+ def columns; [:id]; end
1024
+
1025
+ validates_each :id do |o, a, v|
1026
+ o.errors[a] << 'blah' unless v == 5
1027
+ end
1028
+ end
1029
+ @m = @c.load(:id => 4)
1030
+ MODEL_DB.reset
1031
+ end
1032
+
1033
+ deprec_specify "should save regardless of validations" do
1034
+ @m.should_not be_valid
1035
+ @m.save!
1036
+ MODEL_DB.sqls.should == ['UPDATE people SET id = 4 WHERE (id = 4)']
1037
+ end
1038
+ end
1039
+
1040
+ describe "Model#save" do
1041
+ before do
1042
+ @c = Class.new(Sequel::Model(:people)) do
1043
+ columns :id
1044
+
1045
+ def validate
1046
+ errors[:id] << 'blah' unless id == 5
1047
+ end
1048
+ end
1049
+ @m = @c.load(:id => 4)
1050
+ MODEL_DB.reset
1051
+ end
1052
+
1053
+ specify "should save only if validations pass" do
1054
+ @m.raise_on_save_failure = false
1055
+ @m.should_not be_valid
1056
+ @m.save
1057
+ MODEL_DB.sqls.should be_empty
1058
+
1059
+ @m.id = 5
1060
+ @m.should be_valid
1061
+ @m.save.should_not be_false
1062
+ MODEL_DB.sqls.should == ['UPDATE people SET id = 5 WHERE (id = 5)']
1063
+ end
1064
+
1065
+ specify "should skip validations if the :validate=>false option is used" do
1066
+ @m.raise_on_save_failure = false
1067
+ @m.should_not be_valid
1068
+ @m.save(:validate=>false)
1069
+ MODEL_DB.sqls.should == ['UPDATE people SET id = 4 WHERE (id = 4)']
1070
+ end
1071
+
1072
+ specify "should raise error if validations fail and raise_on_save_faiure is true" do
1073
+ proc{@m.save}.should raise_error(Sequel::ValidationFailed)
1074
+ end
1075
+
1076
+ specify "should return nil if validations fail and raise_on_save_faiure is false" do
1077
+ @m.raise_on_save_failure = false
1078
+ @m.save.should == nil
1079
+ end
1080
+ end