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
@@ -1,13 +1,21 @@
1
1
  require 'rubygems'
2
2
  unless Object.const_defined?('Sequel')
3
3
  $:.unshift(File.join(File.dirname(__FILE__), "../../lib/"))
4
- require 'sequel_core'
4
+ require 'sequel/core'
5
5
  end
6
6
  unless Sequel.const_defined?('Model')
7
7
  $:.unshift(File.join(File.dirname(__FILE__), "../../lib/"))
8
- require 'sequel_model'
8
+ require 'sequel/model'
9
9
  end
10
10
 
11
+ Sequel.virtual_row_instance_eval = true
12
+
13
+ extensions = %w'string_date_time inflector pagination query pretty_table blank migration'
14
+ plugins = {:hook_class_methods=>[], :schema=>[], :validation_class_methods=>[]}
15
+
16
+ extensions.each{|e| require "sequel/extensions/#{e}"}
17
+ plugins.each{|p, opts| Sequel::Model.plugin(p, *opts)}
18
+
11
19
  class MockDataset < Sequel::Dataset
12
20
  def insert(*args)
13
21
  @db.execute insert_sql(*args)
@@ -55,9 +63,9 @@ class MockDatabase < Sequel::Database
55
63
  end
56
64
  end
57
65
 
58
- def transaction; yield; end
66
+ def transaction(opts={}); yield; end
59
67
 
60
- def dataset; MockDataset.new(self); end
68
+ def dataset(opts=nil); MockDataset.new(self, opts); end
61
69
  end
62
70
 
63
71
  class << Sequel::Model
@@ -79,3 +87,4 @@ class << Sequel::Model
79
87
  end
80
88
 
81
89
  Sequel::Model.db = MODEL_DB = MockDatabase.new
90
+ Sequel::Model.use_transactions = false
@@ -0,0 +1,93 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ context "String#to_time" do
4
+ specify "should convert the string into a Time object" do
5
+ "2007-07-11".to_time.should == Time.parse("2007-07-11")
6
+ "06:30".to_time.should == Time.parse("06:30")
7
+ end
8
+
9
+ specify "should raise InvalidValue for an invalid time" do
10
+ proc {'0000-00-00'.to_time}.should raise_error(Sequel::InvalidValue)
11
+ end
12
+ end
13
+
14
+ context "String#to_date" do
15
+ after do
16
+ Sequel.convert_two_digit_years = true
17
+ end
18
+
19
+ specify "should convert the string into a Date object" do
20
+ "2007-07-11".to_date.should == Date.parse("2007-07-11")
21
+ end
22
+
23
+ specify "should convert 2 digit years by default" do
24
+ "July 11, 07".to_date.should == Date.parse("2007-07-11")
25
+ end
26
+
27
+ specify "should not convert 2 digit years if set not to" do
28
+ Sequel.convert_two_digit_years = false
29
+ "July 11, 07".to_date.should == Date.parse("0007-07-11")
30
+ end
31
+
32
+ specify "should raise InvalidValue for an invalid date" do
33
+ proc {'0000-00-00'.to_date}.should raise_error(Sequel::InvalidValue)
34
+ end
35
+ end
36
+
37
+ context "String#to_datetime" do
38
+ after do
39
+ Sequel.convert_two_digit_years = true
40
+ end
41
+
42
+ specify "should convert the string into a DateTime object" do
43
+ "2007-07-11 10:11:12a".to_datetime.should == DateTime.parse("2007-07-11 10:11:12a")
44
+ end
45
+
46
+ specify "should convert 2 digit years by default" do
47
+ "July 11, 07 10:11:12a".to_datetime.should == DateTime.parse("2007-07-11 10:11:12a")
48
+ end
49
+
50
+ specify "should not convert 2 digit years if set not to" do
51
+ Sequel.convert_two_digit_years = false
52
+ "July 11, 07 10:11:12a".to_datetime.should == DateTime.parse("0007-07-11 10:11:12a")
53
+ end
54
+
55
+ specify "should raise InvalidValue for an invalid date" do
56
+ proc {'0000-00-00'.to_datetime}.should raise_error(Sequel::InvalidValue)
57
+ end
58
+ end
59
+
60
+ context "String#to_sequel_time" do
61
+ after do
62
+ Sequel.datetime_class = Time
63
+ Sequel.convert_two_digit_years = true
64
+ end
65
+
66
+ specify "should convert the string into a Time object by default" do
67
+ "2007-07-11 10:11:12a".to_sequel_time.class.should == Time
68
+ "2007-07-11 10:11:12a".to_sequel_time.should == Time.parse("2007-07-11 10:11:12a")
69
+ end
70
+
71
+ specify "should convert the string into a DateTime object if that is set" do
72
+ Sequel.datetime_class = DateTime
73
+ "2007-07-11 10:11:12a".to_sequel_time.class.should == DateTime
74
+ "2007-07-11 10:11:12a".to_sequel_time.should == DateTime.parse("2007-07-11 10:11:12a")
75
+ end
76
+
77
+ specify "should convert 2 digit years by default if using DateTime class" do
78
+ Sequel.datetime_class = DateTime
79
+ "July 11, 07 10:11:12a".to_sequel_time.should == DateTime.parse("2007-07-11 10:11:12a")
80
+ end
81
+
82
+ specify "should not convert 2 digit years if set not to when using DateTime class" do
83
+ Sequel.datetime_class = DateTime
84
+ Sequel.convert_two_digit_years = false
85
+ "July 11, 07 10:11:12a".to_sequel_time.should == DateTime.parse("0007-07-11 10:11:12a")
86
+ end
87
+
88
+ specify "should raise InvalidValue for an invalid time" do
89
+ proc {'0000-00-00'.to_sequel_time}.should raise_error(Sequel::InvalidValue)
90
+ Sequel.datetime_class = DateTime
91
+ proc {'0000-00-00'.to_sequel_time}.should raise_error(Sequel::InvalidValue)
92
+ end
93
+ end
@@ -1,82 +1,7 @@
1
1
  require File.join(File.dirname(__FILE__), "spec_helper")
2
2
 
3
- describe Sequel::Model::Validation::Errors do
4
- setup do
5
- @errors = Sequel::Model::Validation::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
3
  describe Sequel::Model do
79
- setup do
4
+ before do
80
5
  @c = Class.new(Sequel::Model) do
81
6
  def self.validates_coolness_of(attr)
82
7
  validates_each(attr) {|o, a, v| o.errors[a] << 'is not cool' if v != :cool}
@@ -190,7 +115,7 @@ describe Sequel::Model do
190
115
  end
191
116
 
192
117
  describe Sequel::Model do
193
- setup do
118
+ before do
194
119
  @c = Class.new(Sequel::Model) do
195
120
  columns :score
196
121
  validates_each :score do |o, a, v|
@@ -220,8 +145,8 @@ describe Sequel::Model do
220
145
  end
221
146
  end
222
147
 
223
- describe Sequel::Model::Validation::Generator do
224
- setup do
148
+ describe Sequel::Plugins::ValidationClassMethods::ClassMethods::Generator do
149
+ before do
225
150
  $testit = nil
226
151
 
227
152
  @c = Class.new(Sequel::Model) do
@@ -232,7 +157,7 @@ describe Sequel::Model::Validation::Generator do
232
157
  end
233
158
 
234
159
  specify "should instance_eval the block, sending everything to its receiver" do
235
- Sequel::Model::Validation::Generator.new(@c) do
160
+ @c.validates do
236
161
  blah
237
162
  end
238
163
  $testit.should == 1324
@@ -240,7 +165,7 @@ describe Sequel::Model::Validation::Generator do
240
165
  end
241
166
 
242
167
  describe Sequel::Model do
243
- setup do
168
+ before do
244
169
  @c = Class.new(Sequel::Model) do
245
170
  columns :value
246
171
 
@@ -625,7 +550,7 @@ describe Sequel::Model do
625
550
  end
626
551
 
627
552
  context "Superclass validations" do
628
- setup do
553
+ before do
629
554
  @c1 = Class.new(Sequel::Model) do
630
555
  columns :value
631
556
  validates_length_of :value, :minimum => 5
@@ -1011,28 +936,8 @@ describe Sequel::Model, "Validations" do
1011
936
 
1012
937
  end
1013
938
 
1014
- describe "Model#save!" do
1015
- setup do
1016
- @c = Class.new(Sequel::Model(:people)) do
1017
- def columns; [:id]; end
1018
-
1019
- validates_each :id do |o, a, v|
1020
- o.errors[a] << 'blah' unless v == 5
1021
- end
1022
- end
1023
- @m = @c.load(:id => 4)
1024
- MODEL_DB.reset
1025
- end
1026
-
1027
- specify "should save regardless of validations" do
1028
- @m.should_not be_valid
1029
- @m.save!
1030
- MODEL_DB.sqls.should == ['UPDATE people SET id = 4 WHERE (id = 4)']
1031
- end
1032
- end
1033
-
1034
939
  describe "Model#save" do
1035
- setup do
940
+ before do
1036
941
  @c = Class.new(Sequel::Model(:people)) do
1037
942
  columns :id
1038
943
 
@@ -1056,6 +961,13 @@ describe "Model#save" do
1056
961
  MODEL_DB.sqls.should == ['UPDATE people SET id = 5 WHERE (id = 5)']
1057
962
  end
1058
963
 
964
+ specify "should skip validations if the :validate=>false option is used" do
965
+ @m.raise_on_save_failure = false
966
+ @m.should_not be_valid
967
+ @m.save(:validate=>false)
968
+ MODEL_DB.sqls.should == ['UPDATE people SET id = 4 WHERE (id = 4)']
969
+ end
970
+
1059
971
  specify "should raise error if validations fail and raise_on_save_faiure is true" do
1060
972
  proc{@m.save}.should raise_error(Sequel::ValidationFailed)
1061
973
  end
@@ -0,0 +1,291 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe "Sequel::Plugins::ValidationHelpers" do
4
+ before do
5
+ @c = Class.new(Sequel::Model) do
6
+ def self.set_validations(&block)
7
+ define_method(:validate, &block)
8
+ end
9
+ columns :value
10
+ end
11
+ @c.plugin :validation_helpers
12
+ @m = @c.new
13
+ end
14
+
15
+ specify "should take an :allow_blank option" do
16
+ @c.set_validations{validates_format(/.+_.+/, :value, :allow_blank=>true)}
17
+ @m.value = 'abc_'
18
+ @m.should_not be_valid
19
+ @m.value = '1_1'
20
+ @m.should be_valid
21
+ o = Object.new
22
+ @m.value = o
23
+ @m.should_not be_valid
24
+ def o.blank?
25
+ true
26
+ end
27
+ @m.should be_valid
28
+ end
29
+
30
+ specify "should take an :allow_missing option" do
31
+ @c.set_validations{validates_format(/.+_.+/, :value, :allow_missing=>true)}
32
+ @m.values.clear
33
+ @m.should be_valid
34
+ @m.value = nil
35
+ @m.should_not be_valid
36
+ @m.value = '1_1'
37
+ @m.should be_valid
38
+ end
39
+
40
+ specify "should take an :allow_nil option" do
41
+ @c.set_validations{validates_format(/.+_.+/, :value, :allow_nil=>true)}
42
+ @m.value = 'abc_'
43
+ @m.should_not be_valid
44
+ @m.value = '1_1'
45
+ @m.should be_valid
46
+ @m.value = nil
47
+ @m.should be_valid
48
+ end
49
+
50
+ specify "should take a :message option" do
51
+ @c.set_validations{validates_format(/.+_.+/, :value, :message=>"is so blah")}
52
+ @m.value = 'abc_'
53
+ @m.should_not be_valid
54
+ @m.errors.full_messages.should == ['value is so blah']
55
+ @m.value = '1_1'
56
+ @m.should be_valid
57
+ end
58
+
59
+ specify "should take multiple attributes in the same call" do
60
+ @c.columns :value, :value2
61
+ @c.set_validations{validates_presence([:value, :value2])}
62
+ @m.should_not be_valid
63
+ @m.value = 1
64
+ @m.should_not be_valid
65
+ @m.value2 = 1
66
+ @m.should be_valid
67
+ end
68
+
69
+ specify "should support validates_exact_length" do
70
+ @c.set_validations{validates_exact_length(3, :value)}
71
+ @m.should_not be_valid
72
+ @m.value = '123'
73
+ @m.should be_valid
74
+ @m.value = '12'
75
+ @m.should_not be_valid
76
+ @m.value = '1234'
77
+ @m.should_not be_valid
78
+ end
79
+
80
+ specify "should support validate_format" do
81
+ @c.set_validations{validates_format(/.+_.+/, :value)}
82
+ @m.value = 'abc_'
83
+ @m.should_not be_valid
84
+ @m.value = 'abc_def'
85
+ @m.should be_valid
86
+ end
87
+
88
+ specify "should support validates_includes with an array" do
89
+ @c.set_validations{validates_includes([1,2], :value)}
90
+ @m.should_not be_valid
91
+ @m.value = 1
92
+ @m.should be_valid
93
+ @m.value = 1.5
94
+ @m.should_not be_valid
95
+ @m.value = 2
96
+ @m.should be_valid
97
+ @m.value = 3
98
+ @m.should_not be_valid
99
+ end
100
+
101
+ specify "should support validates_includes with a range" do
102
+ @c.set_validations{validates_includes(1..4, :value)}
103
+ @m.should_not be_valid
104
+ @m.value = 1
105
+ @m.should be_valid
106
+ @m.value = 1.5
107
+ @m.should be_valid
108
+ @m.value = 0
109
+ @m.should_not be_valid
110
+ @m.value = 5
111
+ @m.should_not be_valid
112
+ end
113
+
114
+ specify "should supports validates_integer" do
115
+ @c.set_validations{validates_integer(:value)}
116
+ @m.value = 'blah'
117
+ @m.should_not be_valid
118
+ @m.value = '123'
119
+ @m.should be_valid
120
+ @m.value = '123.1231'
121
+ @m.should_not be_valid
122
+ end
123
+
124
+ specify "should support validates_length_range" do
125
+ @c.set_validations{validates_length_range(2..5, :value)}
126
+ @m.should_not be_valid
127
+ @m.value = '12345'
128
+ @m.should be_valid
129
+ @m.value = '1'
130
+ @m.should_not be_valid
131
+ @m.value = '123456'
132
+ @m.should_not be_valid
133
+ end
134
+
135
+ specify "should support validates_max_length" do
136
+ @c.set_validations{validates_max_length(5, :value)}
137
+ @m.should_not be_valid
138
+ @m.value = '12345'
139
+ @m.should be_valid
140
+ @m.value = '123456'
141
+ @m.should_not be_valid
142
+ end
143
+
144
+ specify "should support validates_min_length" do
145
+ @c.set_validations{validates_min_length(5, :value)}
146
+ @m.should_not be_valid
147
+ @m.value = '12345'
148
+ @m.should be_valid
149
+ @m.value = '1234'
150
+ @m.should_not be_valid
151
+ end
152
+
153
+ specify "should support validates_not_string" do
154
+ @c.set_validations{validates_not_string(:value)}
155
+ @m.value = 123
156
+ @m.should be_valid
157
+ @m.value = '123'
158
+ @m.should_not be_valid
159
+ @m.errors.full_messages.should == ['value is a string']
160
+ @m.meta_def(:db_schema){{:value=>{:type=>:integer}}}
161
+ @m.should_not be_valid
162
+ @m.errors.full_messages.should == ['value is not a valid integer']
163
+ end
164
+
165
+ specify "should support validates_numeric" do
166
+ @c.set_validations{validates_numeric(:value)}
167
+ @m.value = 'blah'
168
+ @m.should_not be_valid
169
+ @m.value = '123'
170
+ @m.should be_valid
171
+ @m.value = '123.1231'
172
+ @m.should be_valid
173
+ @m.value = '+1'
174
+ @m.should be_valid
175
+ @m.value = '-1'
176
+ @m.should be_valid
177
+ @m.value = '+1.123'
178
+ @m.should be_valid
179
+ @m.value = '-0.123'
180
+ @m.should be_valid
181
+ @m.value = '-0.123E10'
182
+ @m.should be_valid
183
+ @m.value = '32.123e10'
184
+ @m.should be_valid
185
+ @m.value = '+32.123E10'
186
+ @m.should be_valid
187
+ @m.should be_valid
188
+ @m.value = '.0123'
189
+ end
190
+
191
+ specify "should support validates_presence" do
192
+ @c.set_validations{validates_presence(:value)}
193
+ @m.should_not be_valid
194
+ @m.value = ''
195
+ @m.should_not be_valid
196
+ @m.value = 1234
197
+ @m.should be_valid
198
+ @m.value = nil
199
+ @m.should_not be_valid
200
+ @m.value = true
201
+ @m.should be_valid
202
+ @m.value = false
203
+ @m.should be_valid
204
+ @m.value = Time.now
205
+ @m.should be_valid
206
+ end
207
+
208
+ it "should support validates_unique with a single attribute" do
209
+ @c.columns(:id, :username, :password)
210
+ @c.set_dataset MODEL_DB[:items]
211
+ @c.set_validations{validates_unique(:username)}
212
+ @c.dataset.extend(Module.new {
213
+ def fetch_rows(sql)
214
+ @db << sql
215
+
216
+ case sql
217
+ when /COUNT.*username = '0records'/
218
+ yield({:v => 0})
219
+ when /COUNT.*username = '1record'/
220
+ yield({:v => 1})
221
+ end
222
+ end
223
+ })
224
+
225
+ @user = @c.new(:username => "0records", :password => "anothertest")
226
+ @user.should be_valid
227
+ @user = @c.load(:id=>3, :username => "0records", :password => "anothertest")
228
+ @user.should be_valid
229
+
230
+ @user = @c.new(:username => "1record", :password => "anothertest")
231
+ @user.should_not be_valid
232
+ @user.errors.full_messages.should == ['username is already taken']
233
+ @user = @c.load(:id=>4, :username => "1record", :password => "anothertest")
234
+ @user.should_not be_valid
235
+ @user.errors.full_messages.should == ['username is already taken']
236
+
237
+ ds1 = @c.dataset.filter([[:username, '0records']])
238
+ ds2 = ds1.exclude(:id=>1)
239
+ @c.dataset.should_receive(:filter).with([[:username, '0records']]).twice.and_return(ds1)
240
+ ds1.should_receive(:exclude).with(:id=>1).once.and_return(ds2)
241
+
242
+ @user = @c.load(:id=>1, :username => "0records", :password => "anothertest")
243
+ @user.should be_valid
244
+ MODEL_DB.sqls.last.should == "SELECT COUNT(*) FROM items WHERE ((username = '0records') AND (id != 1)) LIMIT 1"
245
+ @user = @c.new(:username => "0records", :password => "anothertest")
246
+ @user.should be_valid
247
+ MODEL_DB.sqls.last.should == "SELECT COUNT(*) FROM items WHERE (username = '0records') LIMIT 1"
248
+ end
249
+
250
+ it "should support validates_unique with multiple attributes" do
251
+ @c.columns(:id, :username, :password)
252
+ @c.set_dataset MODEL_DB[:items]
253
+ @c.set_validations{validates_unique([:username, :password])}
254
+ @c.dataset.extend(Module.new {
255
+ def fetch_rows(sql)
256
+ @db << sql
257
+
258
+ case sql
259
+ when /COUNT.*username = '0records'/
260
+ yield({:v => 0})
261
+ when /COUNT.*username = '1record'/
262
+ yield({:v => 1})
263
+ end
264
+ end
265
+ })
266
+
267
+ @user = @c.new(:username => "0records", :password => "anothertest")
268
+ @user.should be_valid
269
+ @user = @c.load(:id=>3, :username => "0records", :password => "anothertest")
270
+ @user.should be_valid
271
+
272
+ @user = @c.new(:username => "1record", :password => "anothertest")
273
+ @user.should_not be_valid
274
+ @user.errors.full_messages.should == ['username and password is already taken']
275
+ @user = @c.load(:id=>4, :username => "1record", :password => "anothertest")
276
+ @user.should_not be_valid
277
+ @user.errors.full_messages.should == ['username and password is already taken']
278
+
279
+ ds1 = @c.dataset.filter([[:username, '0records'], [:password, 'anothertest']])
280
+ ds2 = ds1.exclude(:id=>1)
281
+ @c.dataset.should_receive(:filter).with([[:username, '0records'], [:password, 'anothertest']]).twice.and_return(ds1)
282
+ ds1.should_receive(:exclude).with(:id=>1).once.and_return(ds2)
283
+
284
+ @user = @c.load(:id=>1, :username => "0records", :password => "anothertest")
285
+ @user.should be_valid
286
+ MODEL_DB.sqls.last.should == "SELECT COUNT(*) FROM items WHERE (((username = '0records') AND (password = 'anothertest')) AND (id != 1)) LIMIT 1"
287
+ @user = @c.new(:username => "0records", :password => "anothertest")
288
+ @user.should be_valid
289
+ MODEL_DB.sqls.last.should == "SELECT COUNT(*) FROM items WHERE ((username = '0records') AND (password = 'anothertest')) LIMIT 1"
290
+ end
291
+ end