sequel 2.11.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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