viking-sequel 3.10.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.
- data/CHANGELOG +3134 -0
- data/COPYING +19 -0
- data/README.rdoc +723 -0
- data/Rakefile +193 -0
- data/bin/sequel +196 -0
- data/doc/advanced_associations.rdoc +644 -0
- data/doc/cheat_sheet.rdoc +218 -0
- data/doc/dataset_basics.rdoc +106 -0
- data/doc/dataset_filtering.rdoc +158 -0
- data/doc/opening_databases.rdoc +296 -0
- data/doc/prepared_statements.rdoc +104 -0
- data/doc/reflection.rdoc +84 -0
- data/doc/release_notes/1.0.txt +38 -0
- data/doc/release_notes/1.1.txt +143 -0
- data/doc/release_notes/1.3.txt +101 -0
- data/doc/release_notes/1.4.0.txt +53 -0
- data/doc/release_notes/1.5.0.txt +155 -0
- data/doc/release_notes/2.0.0.txt +298 -0
- data/doc/release_notes/2.1.0.txt +271 -0
- data/doc/release_notes/2.10.0.txt +328 -0
- data/doc/release_notes/2.11.0.txt +215 -0
- data/doc/release_notes/2.12.0.txt +534 -0
- data/doc/release_notes/2.2.0.txt +253 -0
- data/doc/release_notes/2.3.0.txt +88 -0
- data/doc/release_notes/2.4.0.txt +106 -0
- data/doc/release_notes/2.5.0.txt +137 -0
- data/doc/release_notes/2.6.0.txt +157 -0
- data/doc/release_notes/2.7.0.txt +166 -0
- data/doc/release_notes/2.8.0.txt +171 -0
- data/doc/release_notes/2.9.0.txt +97 -0
- data/doc/release_notes/3.0.0.txt +221 -0
- data/doc/release_notes/3.1.0.txt +406 -0
- data/doc/release_notes/3.10.0.txt +286 -0
- data/doc/release_notes/3.2.0.txt +268 -0
- data/doc/release_notes/3.3.0.txt +192 -0
- data/doc/release_notes/3.4.0.txt +325 -0
- data/doc/release_notes/3.5.0.txt +510 -0
- data/doc/release_notes/3.6.0.txt +366 -0
- data/doc/release_notes/3.7.0.txt +179 -0
- data/doc/release_notes/3.8.0.txt +151 -0
- data/doc/release_notes/3.9.0.txt +233 -0
- data/doc/schema.rdoc +36 -0
- data/doc/sharding.rdoc +113 -0
- data/doc/virtual_rows.rdoc +205 -0
- data/lib/sequel.rb +1 -0
- data/lib/sequel/adapters/ado.rb +90 -0
- data/lib/sequel/adapters/ado/mssql.rb +30 -0
- data/lib/sequel/adapters/amalgalite.rb +176 -0
- data/lib/sequel/adapters/db2.rb +139 -0
- data/lib/sequel/adapters/dbi.rb +113 -0
- data/lib/sequel/adapters/do.rb +188 -0
- data/lib/sequel/adapters/do/mysql.rb +49 -0
- data/lib/sequel/adapters/do/postgres.rb +91 -0
- data/lib/sequel/adapters/do/sqlite.rb +40 -0
- data/lib/sequel/adapters/firebird.rb +283 -0
- data/lib/sequel/adapters/informix.rb +77 -0
- data/lib/sequel/adapters/jdbc.rb +587 -0
- data/lib/sequel/adapters/jdbc/as400.rb +58 -0
- data/lib/sequel/adapters/jdbc/h2.rb +133 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +57 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +78 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +50 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +108 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +55 -0
- data/lib/sequel/adapters/mysql.rb +421 -0
- data/lib/sequel/adapters/odbc.rb +143 -0
- data/lib/sequel/adapters/odbc/mssql.rb +42 -0
- data/lib/sequel/adapters/openbase.rb +64 -0
- data/lib/sequel/adapters/oracle.rb +131 -0
- data/lib/sequel/adapters/postgres.rb +504 -0
- data/lib/sequel/adapters/shared/mssql.rb +490 -0
- data/lib/sequel/adapters/shared/mysql.rb +498 -0
- data/lib/sequel/adapters/shared/oracle.rb +195 -0
- data/lib/sequel/adapters/shared/postgres.rb +830 -0
- data/lib/sequel/adapters/shared/progress.rb +44 -0
- data/lib/sequel/adapters/shared/sqlite.rb +389 -0
- data/lib/sequel/adapters/sqlite.rb +224 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +84 -0
- data/lib/sequel/connection_pool.rb +99 -0
- data/lib/sequel/connection_pool/sharded_single.rb +84 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
- data/lib/sequel/connection_pool/single.rb +29 -0
- data/lib/sequel/connection_pool/threaded.rb +150 -0
- data/lib/sequel/core.rb +293 -0
- data/lib/sequel/core_sql.rb +241 -0
- data/lib/sequel/database.rb +1079 -0
- data/lib/sequel/database/schema_generator.rb +327 -0
- data/lib/sequel/database/schema_methods.rb +203 -0
- data/lib/sequel/database/schema_sql.rb +320 -0
- data/lib/sequel/dataset.rb +32 -0
- data/lib/sequel/dataset/actions.rb +441 -0
- data/lib/sequel/dataset/features.rb +86 -0
- data/lib/sequel/dataset/graph.rb +254 -0
- data/lib/sequel/dataset/misc.rb +119 -0
- data/lib/sequel/dataset/mutation.rb +64 -0
- data/lib/sequel/dataset/prepared_statements.rb +227 -0
- data/lib/sequel/dataset/query.rb +709 -0
- data/lib/sequel/dataset/sql.rb +996 -0
- data/lib/sequel/exceptions.rb +51 -0
- data/lib/sequel/extensions/blank.rb +43 -0
- data/lib/sequel/extensions/inflector.rb +242 -0
- data/lib/sequel/extensions/looser_typecasting.rb +21 -0
- data/lib/sequel/extensions/migration.rb +239 -0
- data/lib/sequel/extensions/named_timezones.rb +61 -0
- data/lib/sequel/extensions/pagination.rb +100 -0
- data/lib/sequel/extensions/pretty_table.rb +82 -0
- data/lib/sequel/extensions/query.rb +52 -0
- data/lib/sequel/extensions/schema_dumper.rb +271 -0
- data/lib/sequel/extensions/sql_expr.rb +122 -0
- data/lib/sequel/extensions/string_date_time.rb +46 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +48 -0
- data/lib/sequel/metaprogramming.rb +9 -0
- data/lib/sequel/model.rb +120 -0
- data/lib/sequel/model/associations.rb +1514 -0
- data/lib/sequel/model/base.rb +1069 -0
- data/lib/sequel/model/default_inflections.rb +45 -0
- data/lib/sequel/model/errors.rb +39 -0
- data/lib/sequel/model/exceptions.rb +21 -0
- data/lib/sequel/model/inflections.rb +162 -0
- data/lib/sequel/model/plugins.rb +70 -0
- data/lib/sequel/plugins/active_model.rb +59 -0
- data/lib/sequel/plugins/association_dependencies.rb +103 -0
- data/lib/sequel/plugins/association_proxies.rb +41 -0
- data/lib/sequel/plugins/boolean_readers.rb +53 -0
- data/lib/sequel/plugins/caching.rb +141 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +214 -0
- data/lib/sequel/plugins/composition.rb +138 -0
- data/lib/sequel/plugins/force_encoding.rb +72 -0
- data/lib/sequel/plugins/hook_class_methods.rb +126 -0
- data/lib/sequel/plugins/identity_map.rb +116 -0
- data/lib/sequel/plugins/instance_filters.rb +98 -0
- data/lib/sequel/plugins/instance_hooks.rb +57 -0
- data/lib/sequel/plugins/lazy_attributes.rb +77 -0
- data/lib/sequel/plugins/many_through_many.rb +208 -0
- data/lib/sequel/plugins/nested_attributes.rb +206 -0
- data/lib/sequel/plugins/optimistic_locking.rb +81 -0
- data/lib/sequel/plugins/rcte_tree.rb +281 -0
- data/lib/sequel/plugins/schema.rb +66 -0
- data/lib/sequel/plugins/serialization.rb +166 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +74 -0
- data/lib/sequel/plugins/subclasses.rb +45 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +61 -0
- data/lib/sequel/plugins/timestamps.rb +87 -0
- data/lib/sequel/plugins/touch.rb +118 -0
- data/lib/sequel/plugins/typecast_on_load.rb +72 -0
- data/lib/sequel/plugins/validation_class_methods.rb +405 -0
- data/lib/sequel/plugins/validation_helpers.rb +223 -0
- data/lib/sequel/sql.rb +1020 -0
- data/lib/sequel/timezones.rb +161 -0
- data/lib/sequel/version.rb +12 -0
- data/lib/sequel_core.rb +1 -0
- data/lib/sequel_model.rb +1 -0
- data/spec/adapters/firebird_spec.rb +407 -0
- data/spec/adapters/informix_spec.rb +97 -0
- data/spec/adapters/mssql_spec.rb +403 -0
- data/spec/adapters/mysql_spec.rb +1019 -0
- data/spec/adapters/oracle_spec.rb +286 -0
- data/spec/adapters/postgres_spec.rb +969 -0
- data/spec/adapters/spec_helper.rb +51 -0
- data/spec/adapters/sqlite_spec.rb +432 -0
- data/spec/core/connection_pool_spec.rb +808 -0
- data/spec/core/core_sql_spec.rb +417 -0
- data/spec/core/database_spec.rb +1662 -0
- data/spec/core/dataset_spec.rb +3827 -0
- data/spec/core/expression_filters_spec.rb +595 -0
- data/spec/core/object_graph_spec.rb +296 -0
- data/spec/core/schema_generator_spec.rb +159 -0
- data/spec/core/schema_spec.rb +830 -0
- data/spec/core/spec_helper.rb +56 -0
- data/spec/core/version_spec.rb +7 -0
- data/spec/extensions/active_model_spec.rb +76 -0
- data/spec/extensions/association_dependencies_spec.rb +127 -0
- data/spec/extensions/association_proxies_spec.rb +50 -0
- data/spec/extensions/blank_spec.rb +67 -0
- data/spec/extensions/boolean_readers_spec.rb +92 -0
- data/spec/extensions/caching_spec.rb +250 -0
- data/spec/extensions/class_table_inheritance_spec.rb +252 -0
- data/spec/extensions/composition_spec.rb +194 -0
- data/spec/extensions/force_encoding_spec.rb +117 -0
- data/spec/extensions/hook_class_methods_spec.rb +470 -0
- data/spec/extensions/identity_map_spec.rb +202 -0
- data/spec/extensions/inflector_spec.rb +181 -0
- data/spec/extensions/instance_filters_spec.rb +55 -0
- data/spec/extensions/instance_hooks_spec.rb +133 -0
- data/spec/extensions/lazy_attributes_spec.rb +153 -0
- data/spec/extensions/looser_typecasting_spec.rb +39 -0
- data/spec/extensions/many_through_many_spec.rb +884 -0
- data/spec/extensions/migration_spec.rb +332 -0
- data/spec/extensions/named_timezones_spec.rb +72 -0
- data/spec/extensions/nested_attributes_spec.rb +396 -0
- data/spec/extensions/optimistic_locking_spec.rb +100 -0
- data/spec/extensions/pagination_spec.rb +99 -0
- data/spec/extensions/pretty_table_spec.rb +91 -0
- data/spec/extensions/query_spec.rb +85 -0
- data/spec/extensions/rcte_tree_spec.rb +205 -0
- data/spec/extensions/schema_dumper_spec.rb +357 -0
- data/spec/extensions/schema_spec.rb +127 -0
- data/spec/extensions/serialization_spec.rb +209 -0
- data/spec/extensions/single_table_inheritance_spec.rb +96 -0
- data/spec/extensions/spec_helper.rb +91 -0
- data/spec/extensions/sql_expr_spec.rb +89 -0
- data/spec/extensions/string_date_time_spec.rb +93 -0
- data/spec/extensions/subclasses_spec.rb +52 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +65 -0
- data/spec/extensions/thread_local_timezones_spec.rb +45 -0
- data/spec/extensions/timestamps_spec.rb +150 -0
- data/spec/extensions/touch_spec.rb +155 -0
- data/spec/extensions/typecast_on_load_spec.rb +69 -0
- data/spec/extensions/validation_class_methods_spec.rb +984 -0
- data/spec/extensions/validation_helpers_spec.rb +438 -0
- data/spec/integration/associations_test.rb +281 -0
- data/spec/integration/database_test.rb +26 -0
- data/spec/integration/dataset_test.rb +963 -0
- data/spec/integration/eager_loader_test.rb +734 -0
- data/spec/integration/model_test.rb +130 -0
- data/spec/integration/plugin_test.rb +814 -0
- data/spec/integration/prepared_statement_test.rb +213 -0
- data/spec/integration/schema_test.rb +361 -0
- data/spec/integration/spec_helper.rb +73 -0
- data/spec/integration/timezone_test.rb +55 -0
- data/spec/integration/transaction_test.rb +122 -0
- data/spec/integration/type_test.rb +96 -0
- data/spec/model/association_reflection_spec.rb +175 -0
- data/spec/model/associations_spec.rb +2633 -0
- data/spec/model/base_spec.rb +418 -0
- data/spec/model/dataset_methods_spec.rb +78 -0
- data/spec/model/eager_loading_spec.rb +1391 -0
- data/spec/model/hooks_spec.rb +240 -0
- data/spec/model/inflector_spec.rb +26 -0
- data/spec/model/model_spec.rb +593 -0
- data/spec/model/plugins_spec.rb +236 -0
- data/spec/model/record_spec.rb +1500 -0
- data/spec/model/spec_helper.rb +97 -0
- data/spec/model/validations_spec.rb +153 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec_config.rb.example +10 -0
- metadata +346 -0
@@ -0,0 +1,69 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe Sequel::Model, "TypecastOnLoad plugin" do
|
4
|
+
before do
|
5
|
+
@db = Sequel::Database.new({})
|
6
|
+
def @db.schema(*args)
|
7
|
+
[[:id, {}], [:y, {:type=>:boolean, :db_type=>'tinyint(1)'}], [:b, {:type=>:integer, :db_type=>'integer'}]]
|
8
|
+
end
|
9
|
+
@c = Class.new(Sequel::Model(@db[:items])) do
|
10
|
+
include(Module.new{def _refresh(ds); values[:b] = b.to_s; self; end})
|
11
|
+
attr_accessor :bset
|
12
|
+
def b=(x)
|
13
|
+
self.bset = true
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
@c.instance_eval do
|
18
|
+
@columns = [:id, :b, :y]
|
19
|
+
def columns; @columns; end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
specify "should call setter method with value when loading the object, for all given columns" do
|
24
|
+
@c.plugin :typecast_on_load, :b
|
25
|
+
o = @c.load(:id=>1, :b=>"1", :y=>"0")
|
26
|
+
o.values.should == {:id=>1, :b=>1, :y=>"0"}
|
27
|
+
o.bset.should == true
|
28
|
+
end
|
29
|
+
|
30
|
+
specify "should call setter method with value when reloading the object, for all given columns" do
|
31
|
+
@c.plugin :typecast_on_load, :b
|
32
|
+
o = @c.new({:id=>1, :b=>"1", :y=>"0"}, true)
|
33
|
+
o.refresh
|
34
|
+
o.values.should == {:id=>1, :b=>1, :y=>"0"}
|
35
|
+
o.bset.should == true
|
36
|
+
end
|
37
|
+
|
38
|
+
specify "should allowing setting columns separately via add_typecast_on_load_columns" do
|
39
|
+
@c.plugin :typecast_on_load
|
40
|
+
@c.load(:id=>1, :b=>"1", :y=>"0").values.should == {:id=>1, :b=>"1", :y=>"0"}
|
41
|
+
@c.add_typecast_on_load_columns :b
|
42
|
+
@c.load(:id=>1, :b=>"1", :y=>"0").values.should == {:id=>1, :b=>1, :y=>"0"}
|
43
|
+
@c.add_typecast_on_load_columns :y
|
44
|
+
@c.load(:id=>1, :b=>"1", :y=>"0").values.should == {:id=>1, :b=>1, :y=>false}
|
45
|
+
end
|
46
|
+
|
47
|
+
specify "should work with subclasses" do
|
48
|
+
@c.plugin :typecast_on_load
|
49
|
+
@c.load(:id=>1, :b=>"1", :y=>"0").values.should == {:id=>1, :b=>"1", :y=>"0"}
|
50
|
+
|
51
|
+
c1 = Class.new(@c)
|
52
|
+
@c.add_typecast_on_load_columns :b
|
53
|
+
@c.load(:id=>1, :b=>"1", :y=>"0").values.should == {:id=>1, :b=>1, :y=>"0"}
|
54
|
+
c1.load(:id=>1, :b=>"1", :y=>"0").values.should == {:id=>1, :b=>"1", :y=>"0"}
|
55
|
+
|
56
|
+
c2 = Class.new(@c)
|
57
|
+
@c.add_typecast_on_load_columns :y
|
58
|
+
@c.load(:id=>1, :b=>"1", :y=>"0").values.should == {:id=>1, :b=>1, :y=>false}
|
59
|
+
c2.load(:id=>1, :b=>"1", :y=>"0").values.should == {:id=>1, :b=>1, :y=>"0"}
|
60
|
+
|
61
|
+
c1.add_typecast_on_load_columns :y
|
62
|
+
c1.load(:id=>1, :b=>"1", :y=>"0").values.should == {:id=>1, :b=>"1", :y=>false}
|
63
|
+
end
|
64
|
+
|
65
|
+
specify "should not mark the object as modified" do
|
66
|
+
@c.plugin :typecast_on_load, :b
|
67
|
+
@c.load(:id=>1, :b=>"1", :y=>"0").modified?.should == false
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,984 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe Sequel::Model do
|
4
|
+
before do
|
5
|
+
@c = Class.new(Sequel::Model) do
|
6
|
+
def self.validates_coolness_of(attr)
|
7
|
+
validates_each(attr) {|o, a, v| o.errors[a] << 'is not cool' if v != :cool}
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
specify "should respond to validates, validations, has_validations?" do
|
13
|
+
@c.should respond_to(:validations)
|
14
|
+
@c.should respond_to(:has_validations?)
|
15
|
+
end
|
16
|
+
|
17
|
+
specify "should acccept validation definitions using validates_each" do
|
18
|
+
@c.validates_each(:xx, :yy) {|o, a, v| o.errors[a] << 'too low' if v < 50}
|
19
|
+
o = @c.new
|
20
|
+
o.should_receive(:xx).once.and_return(40)
|
21
|
+
o.should_receive(:yy).once.and_return(60)
|
22
|
+
o.valid?.should == false
|
23
|
+
o.errors.full_messages.should == ['xx too low']
|
24
|
+
end
|
25
|
+
|
26
|
+
specify "should return true/false for has_validations?" do
|
27
|
+
@c.has_validations?.should == false
|
28
|
+
@c.validates_each(:xx) {1}
|
29
|
+
@c.has_validations?.should == true
|
30
|
+
end
|
31
|
+
|
32
|
+
specify "should validate multiple attributes at once" do
|
33
|
+
o = @c.new
|
34
|
+
def o.xx
|
35
|
+
1
|
36
|
+
end
|
37
|
+
def o.yy
|
38
|
+
2
|
39
|
+
end
|
40
|
+
vals = nil
|
41
|
+
atts = nil
|
42
|
+
@c.validates_each([:xx, :yy]){|obj,a,v| atts=a; vals=v}
|
43
|
+
o.valid?
|
44
|
+
vals.should == [1,2]
|
45
|
+
atts.should == [:xx, :yy]
|
46
|
+
end
|
47
|
+
|
48
|
+
specify "should respect allow_missing option when using multiple attributes" do
|
49
|
+
o = @c.new
|
50
|
+
def o.xx
|
51
|
+
self[:xx]
|
52
|
+
end
|
53
|
+
def o.yy
|
54
|
+
self[:yy]
|
55
|
+
end
|
56
|
+
vals = nil
|
57
|
+
atts = nil
|
58
|
+
@c.validates_each([:xx, :yy], :allow_missing=>true){|obj,a,v| atts=a; vals=v}
|
59
|
+
|
60
|
+
o.values[:xx] = 1
|
61
|
+
o.valid?
|
62
|
+
vals.should == [1,nil]
|
63
|
+
atts.should == [:xx, :yy]
|
64
|
+
|
65
|
+
vals = nil
|
66
|
+
atts = nil
|
67
|
+
o.values.clear
|
68
|
+
o.values[:yy] = 2
|
69
|
+
o.valid?
|
70
|
+
vals.should == [nil, 2]
|
71
|
+
atts.should == [:xx, :yy]
|
72
|
+
|
73
|
+
vals = nil
|
74
|
+
atts = nil
|
75
|
+
o.values.clear
|
76
|
+
o.valid?.should == true
|
77
|
+
vals.should == nil
|
78
|
+
atts.should == nil
|
79
|
+
end
|
80
|
+
|
81
|
+
specify "should overwrite existing validation with the same tag and attribute" do
|
82
|
+
@c.validates_each(:xx, :xx, :tag=>:low) {|o, a, v| o.xxx; o.errors[a] << 'too low' if v < 50}
|
83
|
+
@c.validates_each(:yy, :yy) {|o, a, v| o.yyy; o.errors[a] << 'too low' if v < 50}
|
84
|
+
@c.validates_presence_of(:zz, :zz)
|
85
|
+
@c.validates_length_of(:aa, :aa, :tag=>:blah)
|
86
|
+
o = @c.new
|
87
|
+
def o.zz
|
88
|
+
@a ||= 0
|
89
|
+
@a += 1
|
90
|
+
end
|
91
|
+
def o.aa
|
92
|
+
@b ||= 0
|
93
|
+
@b += 1
|
94
|
+
end
|
95
|
+
o.should_receive(:xx).once.and_return(40)
|
96
|
+
o.should_receive(:yy).once.and_return(60)
|
97
|
+
o.should_receive(:xxx).once
|
98
|
+
o.should_receive(:yyy).twice
|
99
|
+
o.valid?.should == false
|
100
|
+
o.zz.should == 2
|
101
|
+
o.aa.should == 2
|
102
|
+
o.errors.full_messages.should == ['xx too low']
|
103
|
+
end
|
104
|
+
|
105
|
+
specify "should provide a validates method that takes block with validation definitions" do
|
106
|
+
@c.validates do
|
107
|
+
coolness_of :blah
|
108
|
+
end
|
109
|
+
@c.validations[:blah].should_not be_empty
|
110
|
+
o = @c.new
|
111
|
+
o.should_receive(:blah).once.and_return(nil)
|
112
|
+
o.valid?.should == false
|
113
|
+
o.errors.full_messages.should == ['blah is not cool']
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe Sequel::Model do
|
118
|
+
before do
|
119
|
+
@c = Class.new(Sequel::Model)
|
120
|
+
@c.class_eval do
|
121
|
+
columns :score
|
122
|
+
validates_each :score do |o, a, v|
|
123
|
+
o.errors[a] << 'too low' if v < 87
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
@o = @c.new
|
128
|
+
end
|
129
|
+
|
130
|
+
specify "should supply a #valid? method that returns true if validations pass" do
|
131
|
+
@o.score = 50
|
132
|
+
@o.should_not be_valid
|
133
|
+
@o.score = 100
|
134
|
+
@o.should be_valid
|
135
|
+
end
|
136
|
+
|
137
|
+
specify "should provide an errors object" do
|
138
|
+
@o.score = 100
|
139
|
+
@o.should be_valid
|
140
|
+
@o.errors.should be_empty
|
141
|
+
|
142
|
+
@o.score = 86
|
143
|
+
@o.should_not be_valid
|
144
|
+
@o.errors[:score].should == ['too low']
|
145
|
+
@o.errors[:blah].should be_empty
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe Sequel::Plugins::ValidationClassMethods::ClassMethods::Generator do
|
150
|
+
before do
|
151
|
+
$testit = nil
|
152
|
+
|
153
|
+
@c = Class.new(Sequel::Model) do
|
154
|
+
def self.validates_blah
|
155
|
+
$testit = 1324
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
specify "should instance_eval the block, sending everything to its receiver" do
|
161
|
+
@c.validates do
|
162
|
+
blah
|
163
|
+
end
|
164
|
+
$testit.should == 1324
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe Sequel::Model do
|
169
|
+
before do
|
170
|
+
@c = Class.new(Sequel::Model) do
|
171
|
+
columns :value
|
172
|
+
|
173
|
+
def self.filter(*args)
|
174
|
+
o = Object.new
|
175
|
+
def o.count; 2; end
|
176
|
+
o
|
177
|
+
end
|
178
|
+
|
179
|
+
def skip; false; end
|
180
|
+
def dont_skip; true; end
|
181
|
+
end
|
182
|
+
@m = @c.new
|
183
|
+
end
|
184
|
+
|
185
|
+
specify "should validate acceptance_of" do
|
186
|
+
@c.validates_acceptance_of :value
|
187
|
+
@m.should be_valid
|
188
|
+
@m.value = '1'
|
189
|
+
@m.should be_valid
|
190
|
+
end
|
191
|
+
|
192
|
+
specify "should validate acceptance_of with accept" do
|
193
|
+
@c.validates_acceptance_of :value, :accept => 'true'
|
194
|
+
@m.value = '1'
|
195
|
+
@m.should_not be_valid
|
196
|
+
@m.value = 'true'
|
197
|
+
@m.should be_valid
|
198
|
+
end
|
199
|
+
|
200
|
+
specify "should validate acceptance_of with allow_nil => false" do
|
201
|
+
@c.validates_acceptance_of :value, :allow_nil => false
|
202
|
+
@m.should_not be_valid
|
203
|
+
end
|
204
|
+
|
205
|
+
specify "should validate acceptance_of with allow_missing => true" do
|
206
|
+
@c.validates_acceptance_of :value, :allow_missing => true
|
207
|
+
@m.should be_valid
|
208
|
+
end
|
209
|
+
|
210
|
+
specify "should validate acceptance_of with allow_missing => true and allow_nil => false" do
|
211
|
+
@c.validates_acceptance_of :value, :allow_missing => true, :allow_nil => false
|
212
|
+
@m.should be_valid
|
213
|
+
@m.value = nil
|
214
|
+
@m.should_not be_valid
|
215
|
+
end
|
216
|
+
|
217
|
+
specify "should validate acceptance_of with if => true" do
|
218
|
+
@c.validates_acceptance_of :value, :if => :dont_skip
|
219
|
+
@m.value = '0'
|
220
|
+
@m.should_not be_valid
|
221
|
+
end
|
222
|
+
|
223
|
+
specify "should validate acceptance_of with if => false" do
|
224
|
+
@c.validates_acceptance_of :value, :if => :skip
|
225
|
+
@m.value = '0'
|
226
|
+
@m.should be_valid
|
227
|
+
end
|
228
|
+
|
229
|
+
specify "should validate acceptance_of with if proc that evaluates to true" do
|
230
|
+
@c.validates_acceptance_of :value, :if => proc{true}
|
231
|
+
@m.value = '0'
|
232
|
+
@m.should_not be_valid
|
233
|
+
end
|
234
|
+
|
235
|
+
specify "should validate acceptance_of with if proc that evaluates to false" do
|
236
|
+
@c.validates_acceptance_of :value, :if => proc{false}
|
237
|
+
@m.value = '0'
|
238
|
+
@m.should be_valid
|
239
|
+
end
|
240
|
+
|
241
|
+
specify "should raise an error if :if option is not a Symbol, Proc, or nil" do
|
242
|
+
@c.validates_acceptance_of :value, :if => 1
|
243
|
+
@m.value = '0'
|
244
|
+
proc{@m.valid?}.should raise_error(Sequel::Error)
|
245
|
+
end
|
246
|
+
|
247
|
+
specify "should validate confirmation_of" do
|
248
|
+
@c.send(:attr_accessor, :value_confirmation)
|
249
|
+
@c.validates_confirmation_of :value
|
250
|
+
|
251
|
+
@m.value = 'blah'
|
252
|
+
@m.should_not be_valid
|
253
|
+
|
254
|
+
@m.value_confirmation = 'blah'
|
255
|
+
@m.should be_valid
|
256
|
+
end
|
257
|
+
|
258
|
+
specify "should validate confirmation_of with if => true" do
|
259
|
+
@c.send(:attr_accessor, :value_confirmation)
|
260
|
+
@c.validates_confirmation_of :value, :if => :dont_skip
|
261
|
+
|
262
|
+
@m.value = 'blah'
|
263
|
+
@m.should_not be_valid
|
264
|
+
end
|
265
|
+
|
266
|
+
specify "should validate confirmation_of with if => false" do
|
267
|
+
@c.send(:attr_accessor, :value_confirmation)
|
268
|
+
@c.validates_confirmation_of :value, :if => :skip
|
269
|
+
|
270
|
+
@m.value = 'blah'
|
271
|
+
@m.should be_valid
|
272
|
+
end
|
273
|
+
|
274
|
+
specify "should validate confirmation_of with allow_missing => true" do
|
275
|
+
@c.send(:attr_accessor, :value_confirmation)
|
276
|
+
@c.validates_acceptance_of :value, :allow_missing => true
|
277
|
+
@m.should be_valid
|
278
|
+
@m.value_confirmation = 'blah'
|
279
|
+
@m.should be_valid
|
280
|
+
@m.value = nil
|
281
|
+
@m.should_not be_valid
|
282
|
+
end
|
283
|
+
|
284
|
+
specify "should validate format_of" do
|
285
|
+
@c.validates_format_of :value, :with => /.+_.+/
|
286
|
+
@m.value = 'abc_'
|
287
|
+
@m.should_not be_valid
|
288
|
+
@m.value = 'abc_def'
|
289
|
+
@m.should be_valid
|
290
|
+
end
|
291
|
+
|
292
|
+
specify "should raise for validate_format_of without regexp" do
|
293
|
+
proc {@c.validates_format_of :value}.should raise_error(ArgumentError)
|
294
|
+
proc {@c.validates_format_of :value, :with => :blah}.should raise_error(ArgumentError)
|
295
|
+
end
|
296
|
+
|
297
|
+
specify "should validate format_of with if => true" do
|
298
|
+
@c.validates_format_of :value, :with => /_/, :if => :dont_skip
|
299
|
+
|
300
|
+
@m.value = 'a'
|
301
|
+
@m.should_not be_valid
|
302
|
+
end
|
303
|
+
|
304
|
+
specify "should validate format_of with if => false" do
|
305
|
+
@c.validates_format_of :value, :with => /_/, :if => :skip
|
306
|
+
|
307
|
+
@m.value = 'a'
|
308
|
+
@m.should be_valid
|
309
|
+
end
|
310
|
+
|
311
|
+
specify "should validate format_of with allow_missing => true" do
|
312
|
+
@c.validates_format_of :value, :allow_missing => true, :with=>/./
|
313
|
+
@m.should be_valid
|
314
|
+
@m.value = nil
|
315
|
+
@m.should_not be_valid
|
316
|
+
end
|
317
|
+
|
318
|
+
specify "should validate length_of with maximum" do
|
319
|
+
@c.validates_length_of :value, :maximum => 5
|
320
|
+
@m.should_not be_valid
|
321
|
+
@m.value = '12345'
|
322
|
+
@m.should be_valid
|
323
|
+
@m.value = '123456'
|
324
|
+
@m.should_not be_valid
|
325
|
+
end
|
326
|
+
|
327
|
+
specify "should validate length_of with minimum" do
|
328
|
+
@c.validates_length_of :value, :minimum => 5
|
329
|
+
@m.should_not be_valid
|
330
|
+
@m.value = '12345'
|
331
|
+
@m.should be_valid
|
332
|
+
@m.value = '1234'
|
333
|
+
@m.should_not be_valid
|
334
|
+
end
|
335
|
+
|
336
|
+
specify "should validate length_of with within" do
|
337
|
+
@c.validates_length_of :value, :within => 2..5
|
338
|
+
@m.should_not be_valid
|
339
|
+
@m.value = '12345'
|
340
|
+
@m.should be_valid
|
341
|
+
@m.value = '1'
|
342
|
+
@m.should_not be_valid
|
343
|
+
@m.value = '123456'
|
344
|
+
@m.should_not be_valid
|
345
|
+
end
|
346
|
+
|
347
|
+
specify "should validate length_of with is" do
|
348
|
+
@c.validates_length_of :value, :is => 3
|
349
|
+
@m.should_not be_valid
|
350
|
+
@m.value = '123'
|
351
|
+
@m.should be_valid
|
352
|
+
@m.value = '12'
|
353
|
+
@m.should_not be_valid
|
354
|
+
@m.value = '1234'
|
355
|
+
@m.should_not be_valid
|
356
|
+
end
|
357
|
+
|
358
|
+
specify "should validate length_of with allow_nil" do
|
359
|
+
@c.validates_length_of :value, :is => 3, :allow_nil => true
|
360
|
+
@m.should be_valid
|
361
|
+
end
|
362
|
+
|
363
|
+
specify "should validate length_of with if => true" do
|
364
|
+
@c.validates_length_of :value, :is => 3, :if => :dont_skip
|
365
|
+
|
366
|
+
@m.value = 'a'
|
367
|
+
@m.should_not be_valid
|
368
|
+
end
|
369
|
+
|
370
|
+
specify "should validate length_of with if => false" do
|
371
|
+
@c.validates_length_of :value, :is => 3, :if => :skip
|
372
|
+
|
373
|
+
@m.value = 'a'
|
374
|
+
@m.should be_valid
|
375
|
+
end
|
376
|
+
|
377
|
+
specify "should validate length_of with allow_missing => true" do
|
378
|
+
@c.validates_length_of :value, :allow_missing => true, :minimum => 5
|
379
|
+
@m.should be_valid
|
380
|
+
@m.value = nil
|
381
|
+
@m.should_not be_valid
|
382
|
+
end
|
383
|
+
|
384
|
+
specify "should allow multiple calls to validates_length_of with different options without overwriting" do
|
385
|
+
@c.validates_length_of :value, :maximum => 5
|
386
|
+
@c.validates_length_of :value, :minimum => 5
|
387
|
+
@m.should_not be_valid
|
388
|
+
@m.value = '12345'
|
389
|
+
@m.should be_valid
|
390
|
+
@m.value = '123456'
|
391
|
+
@m.should_not be_valid
|
392
|
+
@m.value = '12345'
|
393
|
+
@m.should be_valid
|
394
|
+
@m.value = '1234'
|
395
|
+
@m.should_not be_valid
|
396
|
+
end
|
397
|
+
|
398
|
+
specify "should validate numericality_of" do
|
399
|
+
@c.validates_numericality_of :value
|
400
|
+
@m.value = 'blah'
|
401
|
+
@m.should_not be_valid
|
402
|
+
@m.value = '123'
|
403
|
+
@m.should be_valid
|
404
|
+
@m.value = '123.1231'
|
405
|
+
@m.should be_valid
|
406
|
+
@m.value = '+1'
|
407
|
+
@m.should be_valid
|
408
|
+
@m.value = '-1'
|
409
|
+
@m.should be_valid
|
410
|
+
@m.value = '+1.123'
|
411
|
+
@m.should be_valid
|
412
|
+
@m.value = '-0.123'
|
413
|
+
@m.should be_valid
|
414
|
+
@m.value = '-0.123E10'
|
415
|
+
@m.should be_valid
|
416
|
+
@m.value = '32.123e10'
|
417
|
+
@m.should be_valid
|
418
|
+
@m.value = '+32.123E10'
|
419
|
+
@m.should be_valid
|
420
|
+
@m.should be_valid
|
421
|
+
@m.value = '.0123'
|
422
|
+
end
|
423
|
+
|
424
|
+
specify "should validate numericality_of with only_integer" do
|
425
|
+
@c.validates_numericality_of :value, :only_integer => true
|
426
|
+
@m.value = 'blah'
|
427
|
+
@m.should_not be_valid
|
428
|
+
@m.value = '123'
|
429
|
+
@m.should be_valid
|
430
|
+
@m.value = '123.1231'
|
431
|
+
@m.should_not be_valid
|
432
|
+
end
|
433
|
+
|
434
|
+
specify "should validate numericality_of with if => true" do
|
435
|
+
@c.validates_numericality_of :value, :if => :dont_skip
|
436
|
+
|
437
|
+
@m.value = 'a'
|
438
|
+
@m.should_not be_valid
|
439
|
+
end
|
440
|
+
|
441
|
+
specify "should validate numericality_of with if => false" do
|
442
|
+
@c.validates_numericality_of :value, :if => :skip
|
443
|
+
|
444
|
+
@m.value = 'a'
|
445
|
+
@m.should be_valid
|
446
|
+
end
|
447
|
+
|
448
|
+
specify "should validate numericality_of with allow_missing => true" do
|
449
|
+
@c.validates_numericality_of :value, :allow_missing => true
|
450
|
+
@m.should be_valid
|
451
|
+
@m.value = nil
|
452
|
+
@m.should_not be_valid
|
453
|
+
end
|
454
|
+
|
455
|
+
specify "should validate presence_of" do
|
456
|
+
@c.validates_presence_of :value
|
457
|
+
@m.should_not be_valid
|
458
|
+
@m.value = ''
|
459
|
+
@m.should_not be_valid
|
460
|
+
@m.value = 1234
|
461
|
+
@m.should be_valid
|
462
|
+
@m.value = nil
|
463
|
+
@m.should_not be_valid
|
464
|
+
@m.value = true
|
465
|
+
@m.should be_valid
|
466
|
+
@m.value = false
|
467
|
+
@m.should be_valid
|
468
|
+
end
|
469
|
+
|
470
|
+
specify "should validate inclusion_of with an array" do
|
471
|
+
@c.validates_inclusion_of :value, :in => [1,2]
|
472
|
+
@m.should_not be_valid
|
473
|
+
@m.value = 1
|
474
|
+
@m.should be_valid
|
475
|
+
@m.value = 1.5
|
476
|
+
@m.should_not be_valid
|
477
|
+
@m.value = 2
|
478
|
+
@m.should be_valid
|
479
|
+
@m.value = 3
|
480
|
+
@m.should_not be_valid
|
481
|
+
end
|
482
|
+
|
483
|
+
specify "should validate inclusion_of with a range" do
|
484
|
+
@c.validates_inclusion_of :value, :in => 1..4
|
485
|
+
@m.should_not be_valid
|
486
|
+
@m.value = 1
|
487
|
+
@m.should be_valid
|
488
|
+
@m.value = 1.5
|
489
|
+
@m.should be_valid
|
490
|
+
@m.value = 0
|
491
|
+
@m.should_not be_valid
|
492
|
+
@m.value = 5
|
493
|
+
@m.should_not be_valid
|
494
|
+
end
|
495
|
+
|
496
|
+
specify "should raise an error if inclusion_of doesn't receive a valid :in option" do
|
497
|
+
lambda {
|
498
|
+
@c.validates_inclusion_of :value
|
499
|
+
}.should raise_error(ArgumentError)
|
500
|
+
|
501
|
+
lambda {
|
502
|
+
@c.validates_inclusion_of :value, :in => 1
|
503
|
+
}.should raise_error(ArgumentError)
|
504
|
+
end
|
505
|
+
|
506
|
+
specify "should raise an error if inclusion_of handles :allow_nil too" do
|
507
|
+
@c.validates_inclusion_of :value, :in => 1..4, :allow_nil => true
|
508
|
+
@m.value = nil
|
509
|
+
@m.should be_valid
|
510
|
+
@m.value = 0
|
511
|
+
@m.should_not be_valid
|
512
|
+
end
|
513
|
+
|
514
|
+
specify "should validate presence_of with if => true" do
|
515
|
+
@c.validates_presence_of :value, :if => :dont_skip
|
516
|
+
@m.should_not be_valid
|
517
|
+
end
|
518
|
+
|
519
|
+
specify "should validate presence_of with if => false" do
|
520
|
+
@c.validates_presence_of :value, :if => :skip
|
521
|
+
@m.should be_valid
|
522
|
+
end
|
523
|
+
|
524
|
+
specify "should validate presence_of with allow_missing => true" do
|
525
|
+
@c.validates_presence_of :value, :allow_missing => true
|
526
|
+
@m.should be_valid
|
527
|
+
@m.value = nil
|
528
|
+
@m.should_not be_valid
|
529
|
+
end
|
530
|
+
|
531
|
+
specify "should validate uniqueness_of with if => true" do
|
532
|
+
@c.validates_uniqueness_of :value, :if => :dont_skip
|
533
|
+
|
534
|
+
@m.value = 'a'
|
535
|
+
@m.should_not be_valid
|
536
|
+
end
|
537
|
+
|
538
|
+
specify "should validate uniqueness_of with if => false" do
|
539
|
+
@c.validates_uniqueness_of :value, :if => :skip
|
540
|
+
|
541
|
+
@m.value = 'a'
|
542
|
+
@m.should be_valid
|
543
|
+
end
|
544
|
+
|
545
|
+
specify "should validate uniqueness_of with allow_missing => true" do
|
546
|
+
@c.validates_uniqueness_of :value, :allow_missing => true
|
547
|
+
@m.should be_valid
|
548
|
+
@m.value = nil
|
549
|
+
@m.should_not be_valid
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
context "Superclass validations" do
|
554
|
+
before do
|
555
|
+
@c1 = Class.new(Sequel::Model)
|
556
|
+
@c1.class_eval do
|
557
|
+
columns :value
|
558
|
+
validates_length_of :value, :minimum => 5
|
559
|
+
end
|
560
|
+
|
561
|
+
@c2 = Class.new(@c1)
|
562
|
+
@c2.class_eval do
|
563
|
+
columns :value
|
564
|
+
validates_format_of :value, :with => /^[a-z]+$/
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
specify "should be checked when validating" do
|
569
|
+
o = @c2.new
|
570
|
+
o.value = 'ab'
|
571
|
+
o.valid?.should == false
|
572
|
+
o.errors.full_messages.should == [
|
573
|
+
'value is too short'
|
574
|
+
]
|
575
|
+
|
576
|
+
o.value = '12'
|
577
|
+
o.valid?.should == false
|
578
|
+
o.errors.full_messages.should == [
|
579
|
+
'value is too short',
|
580
|
+
'value is invalid'
|
581
|
+
]
|
582
|
+
|
583
|
+
o.value = 'abcde'
|
584
|
+
o.valid?.should be_true
|
585
|
+
end
|
586
|
+
|
587
|
+
specify "should be skipped if skip_superclass_validations is called" do
|
588
|
+
@c2.skip_superclass_validations
|
589
|
+
|
590
|
+
o = @c2.new
|
591
|
+
o.value = 'ab'
|
592
|
+
o.valid?.should be_true
|
593
|
+
|
594
|
+
o.value = '12'
|
595
|
+
o.valid?.should == false
|
596
|
+
o.errors.full_messages.should == [
|
597
|
+
'value is invalid'
|
598
|
+
]
|
599
|
+
|
600
|
+
o.value = 'abcde'
|
601
|
+
o.valid?.should be_true
|
602
|
+
end
|
603
|
+
end
|
604
|
+
|
605
|
+
context ".validates with block" do
|
606
|
+
specify "should support calling .each" do
|
607
|
+
@c = Class.new(Sequel::Model)
|
608
|
+
@c.class_eval do
|
609
|
+
columns :vvv
|
610
|
+
validates do
|
611
|
+
each :vvv do |o, a, v|
|
612
|
+
o.errors[a] << "is less than zero" if v.to_i < 0
|
613
|
+
end
|
614
|
+
end
|
615
|
+
end
|
616
|
+
|
617
|
+
o = @c.new
|
618
|
+
o.vvv = 1
|
619
|
+
o.should be_valid
|
620
|
+
o.vvv = -1
|
621
|
+
o.should_not be_valid
|
622
|
+
end
|
623
|
+
end
|
624
|
+
|
625
|
+
describe Sequel::Model, "Validations" do
|
626
|
+
|
627
|
+
before(:all) do
|
628
|
+
class ::Person < Sequel::Model
|
629
|
+
columns :id,:name,:first_name,:last_name,:middle_name,:initials,:age, :terms
|
630
|
+
end
|
631
|
+
|
632
|
+
class ::Smurf < Person
|
633
|
+
end
|
634
|
+
|
635
|
+
class ::Cow < Sequel::Model
|
636
|
+
columns :id, :name, :got_milk
|
637
|
+
end
|
638
|
+
|
639
|
+
class ::User < Sequel::Model
|
640
|
+
columns :id, :username, :password
|
641
|
+
end
|
642
|
+
|
643
|
+
class ::Address < Sequel::Model
|
644
|
+
columns :id, :zip_code
|
645
|
+
end
|
646
|
+
end
|
647
|
+
|
648
|
+
it "should validate the acceptance of a column" do
|
649
|
+
class ::Cow < Sequel::Model
|
650
|
+
validations.clear
|
651
|
+
validates_acceptance_of :got_milk, :accept => 'blah', :allow_nil => false
|
652
|
+
end
|
653
|
+
|
654
|
+
@cow = Cow.new
|
655
|
+
@cow.should_not be_valid
|
656
|
+
@cow.errors.full_messages.should == ["got_milk is not accepted"]
|
657
|
+
|
658
|
+
@cow.got_milk = "blah"
|
659
|
+
@cow.should be_valid
|
660
|
+
end
|
661
|
+
|
662
|
+
it "should validate the confirmation of a column" do
|
663
|
+
class ::User < Sequel::Model
|
664
|
+
def password_confirmation
|
665
|
+
"test"
|
666
|
+
end
|
667
|
+
|
668
|
+
validations.clear
|
669
|
+
validates_confirmation_of :password
|
670
|
+
end
|
671
|
+
|
672
|
+
@user = User.new
|
673
|
+
@user.should_not be_valid
|
674
|
+
@user.errors.full_messages.should == ["password is not confirmed"]
|
675
|
+
|
676
|
+
@user.password = "test"
|
677
|
+
@user.should be_valid
|
678
|
+
end
|
679
|
+
|
680
|
+
it "should validate format of column" do
|
681
|
+
class ::Person < Sequel::Model
|
682
|
+
validates_format_of :first_name, :with => /^[a-zA-Z]+$/
|
683
|
+
end
|
684
|
+
|
685
|
+
@person = Person.new :first_name => "Lancelot99"
|
686
|
+
@person.valid?.should be_false
|
687
|
+
@person = Person.new :first_name => "Anita"
|
688
|
+
@person.valid?.should be_true
|
689
|
+
end
|
690
|
+
|
691
|
+
it "should validate length of column" do
|
692
|
+
class ::Person < Sequel::Model
|
693
|
+
validations.clear
|
694
|
+
validates_length_of :first_name, :maximum => 30
|
695
|
+
validates_length_of :last_name, :minimum => 30
|
696
|
+
validates_length_of :middle_name, :within => 1..5
|
697
|
+
validates_length_of :initials, :is => 2
|
698
|
+
end
|
699
|
+
|
700
|
+
@person = Person.new(
|
701
|
+
:first_name => "Anamethatiswaytofreakinglongandwayoverthirtycharacters",
|
702
|
+
:last_name => "Alastnameunderthirtychars",
|
703
|
+
:initials => "LGC",
|
704
|
+
:middle_name => "danger"
|
705
|
+
)
|
706
|
+
|
707
|
+
@person.should_not be_valid
|
708
|
+
@person.errors.full_messages.size.should == 4
|
709
|
+
@person.errors.full_messages.should include(
|
710
|
+
'first_name is too long',
|
711
|
+
'last_name is too short',
|
712
|
+
'middle_name is the wrong length',
|
713
|
+
'initials is the wrong length'
|
714
|
+
)
|
715
|
+
|
716
|
+
@person.first_name = "Lancelot"
|
717
|
+
@person.last_name = "1234567890123456789012345678901"
|
718
|
+
@person.initials = "LC"
|
719
|
+
@person.middle_name = "Will"
|
720
|
+
@person.should be_valid
|
721
|
+
end
|
722
|
+
|
723
|
+
it "should validate that a column doesn't have a string value" do
|
724
|
+
p = Class.new(Sequel::Model)
|
725
|
+
p.class_eval do
|
726
|
+
columns :age, :price, :confirmed
|
727
|
+
self.raise_on_typecast_failure = false
|
728
|
+
validates_not_string :age
|
729
|
+
validates_not_string :confirmed
|
730
|
+
validates_not_string :price, :message=>'is not valid'
|
731
|
+
@db_schema = {:age=>{:type=>:integer}}
|
732
|
+
end
|
733
|
+
|
734
|
+
@person = p.new
|
735
|
+
@person.should be_valid
|
736
|
+
|
737
|
+
@person.confirmed = 't'
|
738
|
+
@person.should_not be_valid
|
739
|
+
@person.errors.full_messages.should == ['confirmed is a string']
|
740
|
+
@person.confirmed = true
|
741
|
+
@person.should be_valid
|
742
|
+
|
743
|
+
@person.age = 'a'
|
744
|
+
@person.should_not be_valid
|
745
|
+
@person.errors.full_messages.should == ['age is not a valid integer']
|
746
|
+
@person.db_schema[:age][:type] = :datetime
|
747
|
+
@person.should_not be_valid
|
748
|
+
@person.errors.full_messages.should == ['age is not a valid datetime']
|
749
|
+
@person.age = 20
|
750
|
+
@person.should be_valid
|
751
|
+
|
752
|
+
@person.price = 'a'
|
753
|
+
@person.should_not be_valid
|
754
|
+
@person.errors.full_messages.should == ['price is not valid']
|
755
|
+
@person.price = 20
|
756
|
+
@person.should be_valid
|
757
|
+
end
|
758
|
+
|
759
|
+
it "should validate numericality of column" do
|
760
|
+
class ::Person < Sequel::Model
|
761
|
+
validations.clear
|
762
|
+
validates_numericality_of :age
|
763
|
+
end
|
764
|
+
|
765
|
+
@person = Person.new :age => "Twenty"
|
766
|
+
@person.should_not be_valid
|
767
|
+
@person.errors.full_messages.should == ['age is not a number']
|
768
|
+
|
769
|
+
@person.age = 20
|
770
|
+
@person.should be_valid
|
771
|
+
end
|
772
|
+
|
773
|
+
it "should validate the presence of a column" do
|
774
|
+
class ::Cow < Sequel::Model
|
775
|
+
validations.clear
|
776
|
+
validates_presence_of :name
|
777
|
+
end
|
778
|
+
|
779
|
+
@cow = Cow.new
|
780
|
+
@cow.should_not be_valid
|
781
|
+
@cow.errors.full_messages.should == ['name is not present']
|
782
|
+
|
783
|
+
@cow.name = "Betsy"
|
784
|
+
@cow.should be_valid
|
785
|
+
end
|
786
|
+
|
787
|
+
it "should validate the uniqueness of a column" do
|
788
|
+
class ::User < Sequel::Model
|
789
|
+
validations.clear
|
790
|
+
validates do
|
791
|
+
uniqueness_of :username
|
792
|
+
end
|
793
|
+
end
|
794
|
+
User.dataset.extend(Module.new {
|
795
|
+
def fetch_rows(sql)
|
796
|
+
@db << sql
|
797
|
+
|
798
|
+
case sql
|
799
|
+
when /COUNT.*username = '0records'/
|
800
|
+
yield({:v => 0})
|
801
|
+
when /COUNT.*username = '2records'/
|
802
|
+
yield({:v => 2})
|
803
|
+
when /COUNT.*username = '1record'/
|
804
|
+
yield({:v => 1})
|
805
|
+
when /username = '1record'/
|
806
|
+
yield({:id => 3, :username => "1record", :password => "test"})
|
807
|
+
end
|
808
|
+
end
|
809
|
+
})
|
810
|
+
|
811
|
+
@user = User.new(:username => "2records", :password => "anothertest")
|
812
|
+
@user.should_not be_valid
|
813
|
+
@user.errors.full_messages.should == ['username is already taken']
|
814
|
+
|
815
|
+
@user = User.new(:username => "1record", :password => "anothertest")
|
816
|
+
@user.should_not be_valid
|
817
|
+
@user.errors.full_messages.should == ['username is already taken']
|
818
|
+
|
819
|
+
@user = User.load(:id=>4, :username => "1record", :password => "anothertest")
|
820
|
+
@user.should_not be_valid
|
821
|
+
@user.errors.full_messages.should == ['username is already taken']
|
822
|
+
|
823
|
+
@user = User.load(:id=>3, :username => "1record", :password => "anothertest")
|
824
|
+
@user.should be_valid
|
825
|
+
@user.errors.full_messages.should == []
|
826
|
+
|
827
|
+
@user = User.new(:username => "0records", :password => "anothertest")
|
828
|
+
@user.should be_valid
|
829
|
+
@user.errors.full_messages.should == []
|
830
|
+
end
|
831
|
+
|
832
|
+
it "should validate the uniqueness of multiple columns" do
|
833
|
+
class ::User < Sequel::Model
|
834
|
+
validations.clear
|
835
|
+
validates do
|
836
|
+
uniqueness_of [:username, :password]
|
837
|
+
end
|
838
|
+
end
|
839
|
+
User.dataset.extend(Module.new {
|
840
|
+
def fetch_rows(sql)
|
841
|
+
@db << sql
|
842
|
+
|
843
|
+
case sql
|
844
|
+
when /COUNT.*username = '0records'/
|
845
|
+
yield({:v => 0})
|
846
|
+
when /COUNT.*username = '2records'/
|
847
|
+
yield({:v => 2})
|
848
|
+
when /COUNT.*username = '1record'/
|
849
|
+
yield({:v => 1})
|
850
|
+
when /username = '1record'/
|
851
|
+
if sql =~ /password = 'anothertest'/
|
852
|
+
yield({:id => 3, :username => "1record", :password => "anothertest"})
|
853
|
+
else
|
854
|
+
yield({:id => 4, :username => "1record", :password => "test"})
|
855
|
+
end
|
856
|
+
end
|
857
|
+
end
|
858
|
+
})
|
859
|
+
|
860
|
+
@user = User.new(:username => "2records", :password => "anothertest")
|
861
|
+
@user.should_not be_valid
|
862
|
+
@user.errors.full_messages.should == ['username and password is already taken']
|
863
|
+
|
864
|
+
@user = User.new(:username => "1record", :password => "anothertest")
|
865
|
+
@user.should_not be_valid
|
866
|
+
@user.errors.full_messages.should == ['username and password is already taken']
|
867
|
+
|
868
|
+
@user = User.load(:id=>4, :username => "1record", :password => "anothertest")
|
869
|
+
@user.should_not be_valid
|
870
|
+
@user.errors.full_messages.should == ['username and password is already taken']
|
871
|
+
|
872
|
+
@user = User.load(:id=>3, :username => "1record", :password => "test")
|
873
|
+
@user.should_not be_valid
|
874
|
+
@user.errors.full_messages.should == ['username and password is already taken']
|
875
|
+
|
876
|
+
@user = User.load(:id=>3, :username => "1record", :password => "anothertest")
|
877
|
+
@user.should be_valid
|
878
|
+
@user.errors.full_messages.should == []
|
879
|
+
|
880
|
+
@user = User.new(:username => "0records", :password => "anothertest")
|
881
|
+
@user.should be_valid
|
882
|
+
@user.errors.full_messages.should == []
|
883
|
+
end
|
884
|
+
|
885
|
+
it "should have a validates block that contains multiple validations" do
|
886
|
+
class ::Person < Sequel::Model
|
887
|
+
validations.clear
|
888
|
+
validates do
|
889
|
+
format_of :first_name, :with => /^[a-zA-Z]+$/
|
890
|
+
length_of :first_name, :maximum => 30
|
891
|
+
end
|
892
|
+
end
|
893
|
+
|
894
|
+
Person.validations[:first_name].size.should == 2
|
895
|
+
|
896
|
+
@person = Person.new :first_name => "Lancelot99"
|
897
|
+
@person.valid?.should be_false
|
898
|
+
|
899
|
+
@person2 = Person.new :first_name => "Wayne"
|
900
|
+
@person2.valid?.should be_true
|
901
|
+
end
|
902
|
+
|
903
|
+
it "should allow 'longhand' validations direcly within the model." do
|
904
|
+
lambda {
|
905
|
+
class ::Person < Sequel::Model
|
906
|
+
validations.clear
|
907
|
+
validates_length_of :first_name, :maximum => 30
|
908
|
+
end
|
909
|
+
}.should_not raise_error
|
910
|
+
Person.validations.length.should eql(1)
|
911
|
+
end
|
912
|
+
|
913
|
+
it "should define a has_validations? method which returns true if the model has validations, false otherwise" do
|
914
|
+
class ::Person < Sequel::Model
|
915
|
+
validations.clear
|
916
|
+
validates do
|
917
|
+
format_of :first_name, :with => /\w+/
|
918
|
+
length_of :first_name, :maximum => 30
|
919
|
+
end
|
920
|
+
end
|
921
|
+
|
922
|
+
class ::Smurf < Person
|
923
|
+
validations.clear
|
924
|
+
end
|
925
|
+
|
926
|
+
Person.should have_validations
|
927
|
+
Smurf.should_not have_validations
|
928
|
+
end
|
929
|
+
|
930
|
+
it "should validate correctly instances initialized with string keys" do
|
931
|
+
class ::Can < Sequel::Model
|
932
|
+
columns :id, :name
|
933
|
+
|
934
|
+
validates_length_of :name, :minimum => 4
|
935
|
+
end
|
936
|
+
|
937
|
+
Can.new('name' => 'ab').should_not be_valid
|
938
|
+
Can.new('name' => 'abcd').should be_valid
|
939
|
+
end
|
940
|
+
|
941
|
+
end
|
942
|
+
|
943
|
+
describe "Model#save" do
|
944
|
+
before do
|
945
|
+
@c = Class.new(Sequel::Model(:people))
|
946
|
+
@c.class_eval do
|
947
|
+
columns :id
|
948
|
+
|
949
|
+
validates_each :id do |o, a, v|
|
950
|
+
o.errors[a] << 'blah' unless v == 5
|
951
|
+
end
|
952
|
+
end
|
953
|
+
@m = @c.load(:id => 4, :x=>6)
|
954
|
+
MODEL_DB.reset
|
955
|
+
end
|
956
|
+
|
957
|
+
specify "should save only if validations pass" do
|
958
|
+
@m.raise_on_save_failure = false
|
959
|
+
@m.should_not be_valid
|
960
|
+
@m.save
|
961
|
+
MODEL_DB.sqls.should be_empty
|
962
|
+
|
963
|
+
@m.id = 5
|
964
|
+
@m.should be_valid
|
965
|
+
@m.save.should_not be_false
|
966
|
+
MODEL_DB.sqls.should == ['UPDATE people SET x = 6 WHERE (id = 5)']
|
967
|
+
end
|
968
|
+
|
969
|
+
specify "should skip validations if the :validate=>false option is used" do
|
970
|
+
@m.raise_on_save_failure = false
|
971
|
+
@m.should_not be_valid
|
972
|
+
@m.save(:validate=>false)
|
973
|
+
MODEL_DB.sqls.should == ['UPDATE people SET x = 6 WHERE (id = 4)']
|
974
|
+
end
|
975
|
+
|
976
|
+
specify "should raise error if validations fail and raise_on_save_faiure is true" do
|
977
|
+
proc{@m.save}.should raise_error(Sequel::ValidationFailed)
|
978
|
+
end
|
979
|
+
|
980
|
+
specify "should return nil if validations fail and raise_on_save_faiure is false" do
|
981
|
+
@m.raise_on_save_failure = false
|
982
|
+
@m.save.should == nil
|
983
|
+
end
|
984
|
+
end
|