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,438 @@
|
|
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 allow a proc for the :message option" do
|
60
|
+
@c.set_validations{validates_format(/.+_.+/, :value, :message=>proc{|f| "doesn't match #{f.inspect}"})}
|
61
|
+
@m.value = 'abc_'
|
62
|
+
@m.should_not be_valid
|
63
|
+
@m.errors.should == {:value=>["doesn't match /.+_.+/"]}
|
64
|
+
end
|
65
|
+
|
66
|
+
specify "should take multiple attributes in the same call" do
|
67
|
+
@c.columns :value, :value2
|
68
|
+
@c.set_validations{validates_presence([:value, :value2])}
|
69
|
+
@m.should_not be_valid
|
70
|
+
@m.value = 1
|
71
|
+
@m.should_not be_valid
|
72
|
+
@m.value2 = 1
|
73
|
+
@m.should be_valid
|
74
|
+
end
|
75
|
+
|
76
|
+
specify "should support modifying default options for all models" do
|
77
|
+
@c.set_validations{validates_presence(:value)}
|
78
|
+
@m.should_not be_valid
|
79
|
+
@m.errors.should == {:value=>['is not present']}
|
80
|
+
o = Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS[:presence].dup
|
81
|
+
Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS[:presence][:message] = lambda{"was not entered"}
|
82
|
+
@m.should_not be_valid
|
83
|
+
@m.errors.should == {:value=>["was not entered"]}
|
84
|
+
@m.value = 1
|
85
|
+
@m.should be_valid
|
86
|
+
|
87
|
+
@m.values.clear
|
88
|
+
Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS[:presence][:allow_missing] = true
|
89
|
+
@m.should be_valid
|
90
|
+
@m.value = nil
|
91
|
+
@m.should_not be_valid
|
92
|
+
@m.errors.should == {:value=>["was not entered"]}
|
93
|
+
|
94
|
+
|
95
|
+
c = Class.new(Sequel::Model)
|
96
|
+
c.class_eval do
|
97
|
+
plugin :validation_helpers
|
98
|
+
set_columns([:value])
|
99
|
+
def validate
|
100
|
+
validates_presence(:value)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
m = c.new(:value=>nil)
|
104
|
+
m.should_not be_valid
|
105
|
+
m.errors.should == {:value=>["was not entered"]}
|
106
|
+
Sequel::Plugins::ValidationHelpers::DEFAULT_OPTIONS[:presence] = o
|
107
|
+
end
|
108
|
+
|
109
|
+
specify "should support modifying default validation options for a particular model" do
|
110
|
+
@c.set_validations{validates_presence(:value)}
|
111
|
+
@m.should_not be_valid
|
112
|
+
@m.errors.should == {:value=>['is not present']}
|
113
|
+
@c.class_eval do
|
114
|
+
def default_validation_helpers_options(type)
|
115
|
+
{:allow_missing=>true, :message=>proc{'was not entered'}}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
@m.value = nil
|
119
|
+
@m.should_not be_valid
|
120
|
+
@m.errors.should == {:value=>["was not entered"]}
|
121
|
+
@m.value = 1
|
122
|
+
@m.should be_valid
|
123
|
+
|
124
|
+
@m.values.clear
|
125
|
+
@m.should be_valid
|
126
|
+
|
127
|
+
c = Class.new(Sequel::Model)
|
128
|
+
c.class_eval do
|
129
|
+
plugin :validation_helpers
|
130
|
+
attr_accessor :value
|
131
|
+
def validate
|
132
|
+
validates_presence(:value)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
m = c.new
|
136
|
+
m.should_not be_valid
|
137
|
+
m.errors.should == {:value=>['is not present']}
|
138
|
+
end
|
139
|
+
|
140
|
+
specify "should support validates_exact_length" do
|
141
|
+
@c.set_validations{validates_exact_length(3, :value)}
|
142
|
+
@m.should_not be_valid
|
143
|
+
@m.value = '123'
|
144
|
+
@m.should be_valid
|
145
|
+
@m.value = '12'
|
146
|
+
@m.should_not be_valid
|
147
|
+
@m.value = '1234'
|
148
|
+
@m.should_not be_valid
|
149
|
+
end
|
150
|
+
|
151
|
+
specify "should support validate_format" do
|
152
|
+
@c.set_validations{validates_format(/.+_.+/, :value)}
|
153
|
+
@m.value = 'abc_'
|
154
|
+
@m.should_not be_valid
|
155
|
+
@m.value = 'abc_def'
|
156
|
+
@m.should be_valid
|
157
|
+
end
|
158
|
+
|
159
|
+
specify "should support validates_includes with an array" do
|
160
|
+
@c.set_validations{validates_includes([1,2], :value)}
|
161
|
+
@m.should_not be_valid
|
162
|
+
@m.value = 1
|
163
|
+
@m.should be_valid
|
164
|
+
@m.value = 1.5
|
165
|
+
@m.should_not be_valid
|
166
|
+
@m.value = 2
|
167
|
+
@m.should be_valid
|
168
|
+
@m.value = 3
|
169
|
+
@m.should_not be_valid
|
170
|
+
end
|
171
|
+
|
172
|
+
specify "should support validates_includes with a range" do
|
173
|
+
@c.set_validations{validates_includes(1..4, :value)}
|
174
|
+
@m.should_not be_valid
|
175
|
+
@m.value = 1
|
176
|
+
@m.should be_valid
|
177
|
+
@m.value = 1.5
|
178
|
+
@m.should be_valid
|
179
|
+
@m.value = 0
|
180
|
+
@m.should_not be_valid
|
181
|
+
@m.value = 5
|
182
|
+
@m.should_not be_valid
|
183
|
+
end
|
184
|
+
|
185
|
+
specify "should supports validates_integer" do
|
186
|
+
@c.set_validations{validates_integer(:value)}
|
187
|
+
@m.value = 'blah'
|
188
|
+
@m.should_not be_valid
|
189
|
+
@m.value = '123'
|
190
|
+
@m.should be_valid
|
191
|
+
@m.value = '123.1231'
|
192
|
+
@m.should_not be_valid
|
193
|
+
end
|
194
|
+
|
195
|
+
specify "should support validates_length_range" do
|
196
|
+
@c.set_validations{validates_length_range(2..5, :value)}
|
197
|
+
@m.should_not be_valid
|
198
|
+
@m.value = '12345'
|
199
|
+
@m.should be_valid
|
200
|
+
@m.value = '1'
|
201
|
+
@m.should_not be_valid
|
202
|
+
@m.value = '123456'
|
203
|
+
@m.should_not be_valid
|
204
|
+
end
|
205
|
+
|
206
|
+
specify "should support validates_max_length" do
|
207
|
+
@c.set_validations{validates_max_length(5, :value)}
|
208
|
+
@m.should_not be_valid
|
209
|
+
@m.value = '12345'
|
210
|
+
@m.should be_valid
|
211
|
+
@m.value = '123456'
|
212
|
+
@m.should_not be_valid
|
213
|
+
end
|
214
|
+
|
215
|
+
specify "should support validates_min_length" do
|
216
|
+
@c.set_validations{validates_min_length(5, :value)}
|
217
|
+
@m.should_not be_valid
|
218
|
+
@m.value = '12345'
|
219
|
+
@m.should be_valid
|
220
|
+
@m.value = '1234'
|
221
|
+
@m.should_not be_valid
|
222
|
+
end
|
223
|
+
|
224
|
+
specify "should support validates_not_string" do
|
225
|
+
@c.set_validations{validates_not_string(:value)}
|
226
|
+
@m.value = 123
|
227
|
+
@m.should be_valid
|
228
|
+
@m.value = '123'
|
229
|
+
@m.should_not be_valid
|
230
|
+
@m.errors.full_messages.should == ['value is a string']
|
231
|
+
@m.meta_def(:db_schema){{:value=>{:type=>:integer}}}
|
232
|
+
@m.should_not be_valid
|
233
|
+
@m.errors.full_messages.should == ['value is not a valid integer']
|
234
|
+
end
|
235
|
+
|
236
|
+
specify "should support validates_numeric" do
|
237
|
+
@c.set_validations{validates_numeric(:value)}
|
238
|
+
@m.value = 'blah'
|
239
|
+
@m.should_not be_valid
|
240
|
+
@m.value = '123'
|
241
|
+
@m.should be_valid
|
242
|
+
@m.value = '123.1231'
|
243
|
+
@m.should be_valid
|
244
|
+
@m.value = '+1'
|
245
|
+
@m.should be_valid
|
246
|
+
@m.value = '-1'
|
247
|
+
@m.should be_valid
|
248
|
+
@m.value = '+1.123'
|
249
|
+
@m.should be_valid
|
250
|
+
@m.value = '-0.123'
|
251
|
+
@m.should be_valid
|
252
|
+
@m.value = '-0.123E10'
|
253
|
+
@m.should be_valid
|
254
|
+
@m.value = '32.123e10'
|
255
|
+
@m.should be_valid
|
256
|
+
@m.value = '+32.123E10'
|
257
|
+
@m.should be_valid
|
258
|
+
@m.should be_valid
|
259
|
+
@m.value = '.0123'
|
260
|
+
end
|
261
|
+
|
262
|
+
specify "should support validates_type" do
|
263
|
+
@c.set_validations{validates_type(Integer, :value)}
|
264
|
+
@m.value = 123
|
265
|
+
@m.should be_valid
|
266
|
+
@m.value = '123'
|
267
|
+
@m.should_not be_valid
|
268
|
+
@m.errors.full_messages.should == ['value is not a Integer']
|
269
|
+
|
270
|
+
@c.set_validations{validates_type(:String, :value)}
|
271
|
+
@m.value = '123'
|
272
|
+
@m.should be_valid
|
273
|
+
@m.value = 123
|
274
|
+
@m.should_not be_valid
|
275
|
+
@m.errors.full_messages.should == ['value is not a String']
|
276
|
+
|
277
|
+
@c.set_validations{validates_type('Integer', :value)}
|
278
|
+
@m.value = 123
|
279
|
+
@m.should be_valid
|
280
|
+
@m.value = 123.05
|
281
|
+
@m.should_not be_valid
|
282
|
+
@m.errors.full_messages.should == ['value is not a Integer']
|
283
|
+
end
|
284
|
+
|
285
|
+
specify "should support validates_presence" do
|
286
|
+
@c.set_validations{validates_presence(:value)}
|
287
|
+
@m.should_not be_valid
|
288
|
+
@m.value = ''
|
289
|
+
@m.should_not be_valid
|
290
|
+
@m.value = 1234
|
291
|
+
@m.should be_valid
|
292
|
+
@m.value = nil
|
293
|
+
@m.should_not be_valid
|
294
|
+
@m.value = true
|
295
|
+
@m.should be_valid
|
296
|
+
@m.value = false
|
297
|
+
@m.should be_valid
|
298
|
+
@m.value = Time.now
|
299
|
+
@m.should be_valid
|
300
|
+
end
|
301
|
+
|
302
|
+
it "should support validates_unique with a single attribute" do
|
303
|
+
@c.columns(:id, :username, :password)
|
304
|
+
@c.set_dataset MODEL_DB[:items]
|
305
|
+
@c.set_validations{validates_unique(:username)}
|
306
|
+
@c.dataset.extend(Module.new {
|
307
|
+
def fetch_rows(sql)
|
308
|
+
@db << sql
|
309
|
+
|
310
|
+
case sql
|
311
|
+
when /COUNT.*username = '0records'/
|
312
|
+
yield({:v => 0})
|
313
|
+
when /COUNT.*username = '1record'/
|
314
|
+
yield({:v => 1})
|
315
|
+
end
|
316
|
+
end
|
317
|
+
})
|
318
|
+
|
319
|
+
@user = @c.new(:username => "0records", :password => "anothertest")
|
320
|
+
@user.should be_valid
|
321
|
+
@user = @c.load(:id=>3, :username => "0records", :password => "anothertest")
|
322
|
+
@user.should be_valid
|
323
|
+
|
324
|
+
@user = @c.new(:username => "1record", :password => "anothertest")
|
325
|
+
@user.should_not be_valid
|
326
|
+
@user.errors.full_messages.should == ['username is already taken']
|
327
|
+
@user = @c.load(:id=>4, :username => "1record", :password => "anothertest")
|
328
|
+
@user.should_not be_valid
|
329
|
+
@user.errors.full_messages.should == ['username is already taken']
|
330
|
+
|
331
|
+
ds1 = @c.dataset.filter([[:username, '0records']])
|
332
|
+
ds2 = ds1.exclude(:id=>1)
|
333
|
+
@c.dataset.should_receive(:filter).with([[:username, '0records']]).twice.and_return(ds1)
|
334
|
+
ds1.should_receive(:exclude).with(:id=>1).once.and_return(ds2)
|
335
|
+
|
336
|
+
@user = @c.load(:id=>1, :username => "0records", :password => "anothertest")
|
337
|
+
@user.should be_valid
|
338
|
+
MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (id != 1)) LIMIT 1"
|
339
|
+
@user = @c.new(:username => "0records", :password => "anothertest")
|
340
|
+
@user.should be_valid
|
341
|
+
MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE (username = '0records') LIMIT 1"
|
342
|
+
end
|
343
|
+
|
344
|
+
it "should support validates_unique with multiple attributes" do
|
345
|
+
@c.columns(:id, :username, :password)
|
346
|
+
@c.set_dataset MODEL_DB[:items]
|
347
|
+
@c.set_validations{validates_unique([:username, :password])}
|
348
|
+
@c.dataset.extend(Module.new {
|
349
|
+
def fetch_rows(sql)
|
350
|
+
@db << sql
|
351
|
+
|
352
|
+
case sql
|
353
|
+
when /COUNT.*username = '0records'/
|
354
|
+
yield({:v => 0})
|
355
|
+
when /COUNT.*username = '1record'/
|
356
|
+
yield({:v => 1})
|
357
|
+
end
|
358
|
+
end
|
359
|
+
})
|
360
|
+
|
361
|
+
@user = @c.new(:username => "0records", :password => "anothertest")
|
362
|
+
@user.should be_valid
|
363
|
+
@user = @c.load(:id=>3, :username => "0records", :password => "anothertest")
|
364
|
+
@user.should be_valid
|
365
|
+
|
366
|
+
@user = @c.new(:username => "1record", :password => "anothertest")
|
367
|
+
@user.should_not be_valid
|
368
|
+
@user.errors.full_messages.should == ['username and password is already taken']
|
369
|
+
@user = @c.load(:id=>4, :username => "1record", :password => "anothertest")
|
370
|
+
@user.should_not be_valid
|
371
|
+
@user.errors.full_messages.should == ['username and password is already taken']
|
372
|
+
|
373
|
+
ds1 = @c.dataset.filter([[:username, '0records'], [:password, 'anothertest']])
|
374
|
+
ds2 = ds1.exclude(:id=>1)
|
375
|
+
@c.dataset.should_receive(:filter).with([[:username, '0records'], [:password, 'anothertest']]).twice.and_return(ds1)
|
376
|
+
ds1.should_receive(:exclude).with(:id=>1).once.and_return(ds2)
|
377
|
+
|
378
|
+
@user = @c.load(:id=>1, :username => "0records", :password => "anothertest")
|
379
|
+
@user.should be_valid
|
380
|
+
MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (password = 'anothertest') AND (id != 1)) LIMIT 1"
|
381
|
+
@user = @c.new(:username => "0records", :password => "anothertest")
|
382
|
+
@user.should be_valid
|
383
|
+
MODEL_DB.sqls.last.should == "SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (password = 'anothertest')) LIMIT 1"
|
384
|
+
end
|
385
|
+
|
386
|
+
it "should support validates_unique with a block" do
|
387
|
+
@c.columns(:id, :username, :password)
|
388
|
+
@c.set_dataset MODEL_DB[:items]
|
389
|
+
@c.set_validations{validates_unique(:username){|ds| ds.filter(:active)}}
|
390
|
+
@c.dataset.extend(Module.new {
|
391
|
+
def fetch_rows (sql)
|
392
|
+
@db << sql
|
393
|
+
yield({:v => 0})
|
394
|
+
end
|
395
|
+
})
|
396
|
+
|
397
|
+
MODEL_DB.reset
|
398
|
+
@c.new(:username => "0records", :password => "anothertest").should be_valid
|
399
|
+
@c.load(:id=>3, :username => "0records", :password => "anothertest").should be_valid
|
400
|
+
MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND active) LIMIT 1",
|
401
|
+
"SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND active AND (id != 3)) LIMIT 1"]
|
402
|
+
end
|
403
|
+
|
404
|
+
it "should support :only_if_modified option for validates_unique, and not check uniqueness for existing records if values haven't changed" do
|
405
|
+
@c.columns(:id, :username, :password)
|
406
|
+
@c.set_dataset MODEL_DB[:items]
|
407
|
+
@c.set_validations{validates_unique([:username, :password], :only_if_modified=>true)}
|
408
|
+
|
409
|
+
@c.dataset.extend(Module.new {
|
410
|
+
def fetch_rows (sql)
|
411
|
+
@db << sql
|
412
|
+
yield({:v => 0})
|
413
|
+
end
|
414
|
+
})
|
415
|
+
|
416
|
+
MODEL_DB.reset
|
417
|
+
@c.new(:username => "0records", :password => "anothertest").should be_valid
|
418
|
+
MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (password = 'anothertest')) LIMIT 1"]
|
419
|
+
MODEL_DB.reset
|
420
|
+
m = @c.load(:id=>3, :username => "0records", :password => "anothertest")
|
421
|
+
m.should be_valid
|
422
|
+
MODEL_DB.sqls.should == []
|
423
|
+
|
424
|
+
m.username = '1'
|
425
|
+
m.should be_valid
|
426
|
+
MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '1') AND (password = 'anothertest') AND (id != 3)) LIMIT 1"]
|
427
|
+
|
428
|
+
m = @c.load(:id=>3, :username => "0records", :password => "anothertest")
|
429
|
+
MODEL_DB.reset
|
430
|
+
m.password = '1'
|
431
|
+
m.should be_valid
|
432
|
+
MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '0records') AND (password = '1') AND (id != 3)) LIMIT 1"]
|
433
|
+
MODEL_DB.reset
|
434
|
+
m.username = '2'
|
435
|
+
m.should be_valid
|
436
|
+
MODEL_DB.sqls.should == ["SELECT COUNT(*) AS count FROM items WHERE ((username = '2') AND (password = '1') AND (id != 3)) LIMIT 1"]
|
437
|
+
end
|
438
|
+
end
|
@@ -0,0 +1,281 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
2
|
+
|
3
|
+
shared_examples_for "regular and composite key associations" do
|
4
|
+
specify "should return no objects if none are associated" do
|
5
|
+
@album.artist.should == nil
|
6
|
+
@artist.albums.should == []
|
7
|
+
@album.tags.should == []
|
8
|
+
@tag.albums.should == []
|
9
|
+
end
|
10
|
+
|
11
|
+
specify "should have add and set methods work any associated objects" do
|
12
|
+
@album.update(:artist => @artist)
|
13
|
+
@album.add_tag(@tag)
|
14
|
+
|
15
|
+
@album.reload
|
16
|
+
@artist.reload
|
17
|
+
@tag.reload
|
18
|
+
|
19
|
+
@album.artist.should == @artist
|
20
|
+
@artist.albums.should == [@album]
|
21
|
+
@album.tags.should == [@tag]
|
22
|
+
@tag.albums.should == [@album]
|
23
|
+
end
|
24
|
+
|
25
|
+
specify "should have remove methods work" do
|
26
|
+
@album.update(:artist => @artist)
|
27
|
+
@album.add_tag(@tag)
|
28
|
+
|
29
|
+
@album.update(:artist => nil)
|
30
|
+
@album.remove_tag(@tag)
|
31
|
+
|
32
|
+
@album.reload
|
33
|
+
@artist.reload
|
34
|
+
@tag.reload
|
35
|
+
|
36
|
+
@album.artist.should == nil
|
37
|
+
@artist.albums.should == []
|
38
|
+
@album.tags.should == []
|
39
|
+
@tag.albums.should == []
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "should have remove_all methods work" do
|
43
|
+
@artist.add_album(@album)
|
44
|
+
@album.add_tag(@tag)
|
45
|
+
|
46
|
+
@artist.remove_all_albums
|
47
|
+
@album.remove_all_tags
|
48
|
+
|
49
|
+
@album.reload
|
50
|
+
@artist.reload
|
51
|
+
@tag.reload
|
52
|
+
|
53
|
+
@album.artist.should == nil
|
54
|
+
@artist.albums.should == []
|
55
|
+
@album.tags.should == []
|
56
|
+
@tag.albums.should == []
|
57
|
+
end
|
58
|
+
|
59
|
+
specify "should eager load via eager correctly" do
|
60
|
+
@album.update(:artist => @artist)
|
61
|
+
@album.add_tag(@tag)
|
62
|
+
|
63
|
+
a = Artist.eager(:albums=>:tags).all
|
64
|
+
a.should == [@artist]
|
65
|
+
a.first.albums.should == [@album]
|
66
|
+
a.first.albums.first.tags.should == [@tag]
|
67
|
+
|
68
|
+
a = Tag.eager(:albums=>:artist).all
|
69
|
+
a.should == [@tag]
|
70
|
+
a.first.albums.should == [@album]
|
71
|
+
a.first.albums.first.artist.should == @artist
|
72
|
+
end
|
73
|
+
|
74
|
+
specify "should eager load via eager_graph correctly" do
|
75
|
+
@album.update(:artist => @artist)
|
76
|
+
@album.add_tag(@tag)
|
77
|
+
|
78
|
+
a = Artist.eager_graph(:albums=>:tags).all
|
79
|
+
a.should == [@artist]
|
80
|
+
a.first.albums.should == [@album]
|
81
|
+
a.first.albums.first.tags.should == [@tag]
|
82
|
+
|
83
|
+
a = Tag.eager_graph(:albums=>:artist).all
|
84
|
+
a.should == [@tag]
|
85
|
+
a.first.albums.should == [@album]
|
86
|
+
a.first.albums.first.artist.should == @artist
|
87
|
+
end
|
88
|
+
|
89
|
+
specify "should work with a many_through_many association" do
|
90
|
+
@album.update(:artist => @artist)
|
91
|
+
@album.add_tag(@tag)
|
92
|
+
|
93
|
+
@album.reload
|
94
|
+
@artist.reload
|
95
|
+
@tag.reload
|
96
|
+
|
97
|
+
@album.tags.should == [@tag]
|
98
|
+
|
99
|
+
a = Artist.eager(:tags).all
|
100
|
+
a.should == [@artist]
|
101
|
+
a.first.tags.should == [@tag]
|
102
|
+
|
103
|
+
a = Artist.eager_graph(:tags).all
|
104
|
+
a.should == [@artist]
|
105
|
+
a.first.tags.should == [@tag]
|
106
|
+
|
107
|
+
a = Album.eager(:artist=>:tags).all
|
108
|
+
a.should == [@album]
|
109
|
+
a.first.artist.should == @artist
|
110
|
+
a.first.artist.tags.should == [@tag]
|
111
|
+
|
112
|
+
a = Album.eager_graph(:artist=>:tags).all
|
113
|
+
a.should == [@album]
|
114
|
+
a.first.artist.should == @artist
|
115
|
+
a.first.artist.tags.should == [@tag]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "Sequel::Model Simple Associations" do
|
120
|
+
before do
|
121
|
+
@db = INTEGRATION_DB
|
122
|
+
@db.create_table!(:artists) do
|
123
|
+
primary_key :id
|
124
|
+
String :name
|
125
|
+
end
|
126
|
+
@db.create_table!(:albums) do
|
127
|
+
primary_key :id
|
128
|
+
String :name
|
129
|
+
foreign_key :artist_id, :artists
|
130
|
+
end
|
131
|
+
@db.create_table!(:tags) do
|
132
|
+
primary_key :id
|
133
|
+
String :name
|
134
|
+
end
|
135
|
+
@db.create_table!(:albums_tags) do
|
136
|
+
foreign_key :album_id, :albums
|
137
|
+
foreign_key :tag_id, :tags
|
138
|
+
end
|
139
|
+
class ::Artist < Sequel::Model(@db)
|
140
|
+
one_to_many :albums
|
141
|
+
plugin :many_through_many
|
142
|
+
Artist.many_through_many :tags, [[:albums, :artist_id, :id], [:albums_tags, :album_id, :tag_id]]
|
143
|
+
end
|
144
|
+
class ::Album < Sequel::Model(@db)
|
145
|
+
many_to_one :artist
|
146
|
+
many_to_many :tags
|
147
|
+
end
|
148
|
+
class ::Tag < Sequel::Model(@db)
|
149
|
+
many_to_many :albums
|
150
|
+
end
|
151
|
+
@album = Album.create(:name=>'Al')
|
152
|
+
@artist = Artist.create(:name=>'Ar')
|
153
|
+
@tag = Tag.create(:name=>'T')
|
154
|
+
end
|
155
|
+
after do
|
156
|
+
@db.drop_table(:albums_tags, :tags, :albums, :artists)
|
157
|
+
[:Tag, :Album, :Artist].each{|x| Object.send(:remove_const, x)}
|
158
|
+
end
|
159
|
+
|
160
|
+
it_should_behave_like "regular and composite key associations"
|
161
|
+
|
162
|
+
specify "should have add method accept hashes and create new records" do
|
163
|
+
@artist.remove_all_albums
|
164
|
+
Album.delete
|
165
|
+
@album = @artist.add_album(:name=>'Al2')
|
166
|
+
Album.first[:name].should == 'Al2'
|
167
|
+
@artist.albums_dataset.first[:name].should == 'Al2'
|
168
|
+
|
169
|
+
@album.remove_all_tags
|
170
|
+
Tag.delete
|
171
|
+
@album.add_tag(:name=>'T2')
|
172
|
+
Tag.first[:name].should == 'T2'
|
173
|
+
@album.tags_dataset.first[:name].should == 'T2'
|
174
|
+
end
|
175
|
+
|
176
|
+
specify "should have remove method accept primary key and remove related album" do
|
177
|
+
@artist.add_album(@album)
|
178
|
+
@artist.reload.remove_album(@album.id)
|
179
|
+
@artist.reload.albums.should == []
|
180
|
+
|
181
|
+
@album.add_tag(@tag)
|
182
|
+
@album.reload.remove_tag(@tag.id)
|
183
|
+
@tag.reload.albums.should == []
|
184
|
+
end
|
185
|
+
|
186
|
+
specify "should have remove method raise an error for one_to_many records if the object isn't already associated" do
|
187
|
+
proc{@artist.remove_album(@album.id)}.should raise_error(Sequel::Error)
|
188
|
+
proc{@artist.remove_album(@album)}.should raise_error(Sequel::Error)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe "Sequel::Model Composite Key Associations" do
|
193
|
+
before do
|
194
|
+
@db = INTEGRATION_DB
|
195
|
+
@db.create_table!(:artists) do
|
196
|
+
Integer :id1
|
197
|
+
Integer :id2
|
198
|
+
String :name
|
199
|
+
primary_key [:id1, :id2]
|
200
|
+
end
|
201
|
+
@db.create_table!(:albums) do
|
202
|
+
Integer :id1
|
203
|
+
Integer :id2
|
204
|
+
String :name
|
205
|
+
Integer :artist_id1
|
206
|
+
Integer :artist_id2
|
207
|
+
foreign_key [:artist_id1, :artist_id2], :artists
|
208
|
+
primary_key [:id1, :id2]
|
209
|
+
end
|
210
|
+
@db.create_table!(:tags) do
|
211
|
+
Integer :id1
|
212
|
+
Integer :id2
|
213
|
+
String :name
|
214
|
+
primary_key [:id1, :id2]
|
215
|
+
end
|
216
|
+
@db.create_table!(:albums_tags) do
|
217
|
+
Integer :album_id1
|
218
|
+
Integer :album_id2
|
219
|
+
Integer :tag_id1
|
220
|
+
Integer :tag_id2
|
221
|
+
foreign_key [:album_id1, :album_id2], :albums
|
222
|
+
foreign_key [:tag_id1, :tag_id2], :tags
|
223
|
+
end
|
224
|
+
class ::Artist < Sequel::Model(@db)
|
225
|
+
set_primary_key :id1, :id2
|
226
|
+
unrestrict_primary_key
|
227
|
+
one_to_many :albums, :key=>[:artist_id1, :artist_id2]
|
228
|
+
plugin :many_through_many
|
229
|
+
Artist.many_through_many :tags, [[:albums, [:artist_id1, :artist_id2], [:id1, :id2]], [:albums_tags, [:album_id1, :album_id2], [:tag_id1, :tag_id2]]]
|
230
|
+
end
|
231
|
+
class ::Album < Sequel::Model(@db)
|
232
|
+
set_primary_key :id1, :id2
|
233
|
+
unrestrict_primary_key
|
234
|
+
many_to_one :artist, :key=>[:artist_id1, :artist_id2]
|
235
|
+
many_to_many :tags, :left_key=>[:album_id1, :album_id2], :right_key=>[:tag_id1, :tag_id2]
|
236
|
+
end
|
237
|
+
class ::Tag < Sequel::Model(@db)
|
238
|
+
set_primary_key :id1, :id2
|
239
|
+
unrestrict_primary_key
|
240
|
+
many_to_many :albums, :right_key=>[:album_id1, :album_id2], :left_key=>[:tag_id1, :tag_id2]
|
241
|
+
end
|
242
|
+
@album = Album.create(:name=>'Al', :id1=>1, :id2=>2)
|
243
|
+
@artist = Artist.create(:name=>'Ar', :id1=>3, :id2=>4)
|
244
|
+
@tag = Tag.create(:name=>'T', :id1=>5, :id2=>6)
|
245
|
+
end
|
246
|
+
after do
|
247
|
+
@db.drop_table(:albums_tags, :tags, :albums, :artists)
|
248
|
+
[:Tag, :Album, :Artist].each{|x| Object.send(:remove_const, x)}
|
249
|
+
end
|
250
|
+
|
251
|
+
it_should_behave_like "regular and composite key associations"
|
252
|
+
|
253
|
+
specify "should have add method accept hashes and create new records" do
|
254
|
+
@artist.remove_all_albums
|
255
|
+
Album.delete
|
256
|
+
@artist.add_album(:id1=>1, :id2=>2, :name=>'Al2')
|
257
|
+
Album.first[:name].should == 'Al2'
|
258
|
+
@artist.albums_dataset.first[:name].should == 'Al2'
|
259
|
+
|
260
|
+
@album.remove_all_tags
|
261
|
+
Tag.delete
|
262
|
+
@album.add_tag(:id1=>1, :id2=>2, :name=>'T2')
|
263
|
+
Tag.first[:name].should == 'T2'
|
264
|
+
@album.tags_dataset.first[:name].should == 'T2'
|
265
|
+
end
|
266
|
+
|
267
|
+
specify "should have remove method accept primary key and remove related album" do
|
268
|
+
@artist.add_album(@album)
|
269
|
+
@artist.reload.remove_album([@album.id1, @album.id2])
|
270
|
+
@artist.reload.albums.should == []
|
271
|
+
|
272
|
+
@album.add_tag(@tag)
|
273
|
+
@album.reload.remove_tag([@tag.id1, @tag.id2])
|
274
|
+
@tag.reload.albums.should == []
|
275
|
+
end
|
276
|
+
|
277
|
+
specify "should have remove method raise an error for one_to_many records if the object isn't already associated" do
|
278
|
+
proc{@artist.remove_album([@album.id1, @album.id2])}.should raise_error(Sequel::Error)
|
279
|
+
proc{@artist.remove_album(@album)}.should raise_error(Sequel::Error)
|
280
|
+
end
|
281
|
+
end
|