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,236 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe Sequel::Model, ".plugin" do
|
4
|
+
before do
|
5
|
+
module Sequel::Plugins
|
6
|
+
module Timestamped
|
7
|
+
module InstanceMethods
|
8
|
+
def get_stamp(*args); @values[:stamp] end
|
9
|
+
def abc; 123; end
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def def; 234; end
|
14
|
+
end
|
15
|
+
|
16
|
+
module DatasetMethods
|
17
|
+
def ghi; 345; end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
@c = Class.new(Sequel::Model(:items))
|
22
|
+
@t = Sequel::Plugins::Timestamped
|
23
|
+
end
|
24
|
+
after do
|
25
|
+
Sequel::Plugins.send(:remove_const, :Timestamped)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should raise LoadError if the plugin is not found" do
|
29
|
+
proc{@c.plugin :something_or_other}.should raise_error(LoadError)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should store the plugin in .plugins" do
|
33
|
+
@c.plugins.should_not include(@t)
|
34
|
+
@c.plugin @t
|
35
|
+
@c.plugins.should include(@t)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should be inherited in subclasses" do
|
39
|
+
@c.plugins.should_not include(@t)
|
40
|
+
c1 = Class.new(@c)
|
41
|
+
@c.plugin @t
|
42
|
+
c2 = Class.new(@c)
|
43
|
+
@c.plugins.should include(@t)
|
44
|
+
c1.plugins.should_not include(@t)
|
45
|
+
c2.plugins.should include(@t)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should accept a symbol and load the module from the Sequel::Plugins namespace" do
|
49
|
+
@c.plugin :timestamped
|
50
|
+
@c.plugins.should include(@t)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should accept a module" do
|
54
|
+
m = Module.new
|
55
|
+
@c.plugin m
|
56
|
+
@c.plugins.should include(m)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should not attempt to load a plugin twice" do
|
60
|
+
@c.plugins.should_not include(@t)
|
61
|
+
@c.plugin @t
|
62
|
+
@c.plugins.reject{|m| m != @t}.length.should == 1
|
63
|
+
@c.plugin @t
|
64
|
+
@c.plugins.reject{|m| m != @t}.length.should == 1
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should call apply and configure if the plugin responds to it, with the args and block used" do
|
68
|
+
m = Module.new do
|
69
|
+
def self.args; @args; end
|
70
|
+
def self.block; @block; end
|
71
|
+
def self.block_call; @block.call; end
|
72
|
+
def self.args2; @args2; end
|
73
|
+
def self.block2; @block2; end
|
74
|
+
def self.block2_call; @block2.call; end
|
75
|
+
def self.apply(model, *args, &block)
|
76
|
+
@args = args
|
77
|
+
@block = block
|
78
|
+
model.send(:define_method, :blah){43}
|
79
|
+
end
|
80
|
+
def self.configure(model, *args, &block)
|
81
|
+
@args2 = args
|
82
|
+
@block2 = block
|
83
|
+
model.send(:define_method, :blag){44}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
b = lambda{42}
|
87
|
+
@c.plugin(m, 123, 1=>2, &b)
|
88
|
+
|
89
|
+
m.args.should == [123, {1=>2}]
|
90
|
+
m.block.should == b
|
91
|
+
m.block_call.should == 42
|
92
|
+
@c.new.blah.should == 43
|
93
|
+
|
94
|
+
m.args2.should == [123, {1=>2}]
|
95
|
+
m.block2.should == b
|
96
|
+
m.block2_call.should == 42
|
97
|
+
@c.new.blag.should == 44
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should call configure even if the plugin has already been loaded" do
|
101
|
+
m = Module.new do
|
102
|
+
@args = []
|
103
|
+
def self.args; @args; end
|
104
|
+
def self.configure(model, *args, &block)
|
105
|
+
@args << [block, *args]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
b = lambda{42}
|
110
|
+
@c.plugin(m, 123, 1=>2, &b)
|
111
|
+
m.args.should == [[b, 123, {1=>2}]]
|
112
|
+
|
113
|
+
b2 = lambda{44}
|
114
|
+
@c.plugin(m, 234, 2=>3, &b2)
|
115
|
+
m.args.should == [[b, 123, {1=>2}], [b2, 234, {2=>3}]]
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should call things in the following order: apply, InstanceMethods, ClassMethods, DatasetMethods, configure" do
|
119
|
+
m = Module.new do
|
120
|
+
@args = []
|
121
|
+
def self.args; @args; end
|
122
|
+
def self.apply(model, *args, &block)
|
123
|
+
@args << :apply
|
124
|
+
end
|
125
|
+
def self.configure(model, *args, &block)
|
126
|
+
@args << :configure
|
127
|
+
end
|
128
|
+
im = Module.new do
|
129
|
+
def self.included(model)
|
130
|
+
model.plugins.last.args << :im
|
131
|
+
end
|
132
|
+
end
|
133
|
+
cm = Module.new do
|
134
|
+
def self.extended(model)
|
135
|
+
model.plugins.last.args << :cm
|
136
|
+
end
|
137
|
+
end
|
138
|
+
dm = Module.new do
|
139
|
+
def self.extended(dataset)
|
140
|
+
dataset.model.plugins.last.args << :dm
|
141
|
+
end
|
142
|
+
end
|
143
|
+
const_set(:InstanceMethods, im)
|
144
|
+
const_set(:ClassMethods, cm)
|
145
|
+
const_set(:DatasetMethods, dm)
|
146
|
+
end
|
147
|
+
|
148
|
+
b = lambda{44}
|
149
|
+
@c.plugin(m, 123, 1=>2, &b)
|
150
|
+
m.args.should == [:apply, :im, :cm, :dm, :configure]
|
151
|
+
@c.plugin(m, 234, 2=>3, &b)
|
152
|
+
m.args.should == [:apply, :im, :cm, :dm, :configure, :configure]
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should include an InstanceMethods module in the class if the plugin includes it" do
|
156
|
+
@c.plugin @t
|
157
|
+
m = @c.new
|
158
|
+
m.should respond_to(:get_stamp)
|
159
|
+
m.should respond_to(:abc)
|
160
|
+
m.abc.should == 123
|
161
|
+
t = Time.now
|
162
|
+
m[:stamp] = t
|
163
|
+
m.get_stamp.should == t
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should extend the class with a ClassMethods module if the plugin includes it" do
|
167
|
+
@c.plugin @t
|
168
|
+
@c.def.should == 234
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should extend the class's dataset with a DatasetMethods module if the plugin includes it" do
|
172
|
+
@c.plugin @t
|
173
|
+
@c.dataset.ghi.should == 345
|
174
|
+
@c.ghi.should == 345
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should save the DatasetMethods module and apply it later if the class doesn't have a dataset" do
|
178
|
+
c = Class.new(Sequel::Model)
|
179
|
+
c.plugin @t
|
180
|
+
proc{c.ghi}.should raise_error(Sequel::Error)
|
181
|
+
c.dataset = MODEL_DB[:i]
|
182
|
+
c.dataset.ghi.should == 345
|
183
|
+
c.ghi.should == 345
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should save the DatasetMethods module and apply it later if the class has a dataset" do
|
187
|
+
@c.plugin @t
|
188
|
+
@c.dataset = MODEL_DB[:i]
|
189
|
+
@c.dataset.ghi.should == 345
|
190
|
+
@c.ghi.should == 345
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should define class methods for all public instance methods in DatasetMethod" do
|
194
|
+
m = Module.new do
|
195
|
+
dm = Module.new do
|
196
|
+
def a; 1; end
|
197
|
+
def b; 2; end
|
198
|
+
end
|
199
|
+
const_set(:DatasetMethods, dm)
|
200
|
+
end
|
201
|
+
@c.plugin m
|
202
|
+
@c.dataset.a.should == 1
|
203
|
+
@c.dataset.b.should == 2
|
204
|
+
@c.a.should == 1
|
205
|
+
@c.b.should == 2
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should define class methods for all public instance methods in DatasetMethod" do
|
209
|
+
m = Module.new do
|
210
|
+
dm = Module.new do
|
211
|
+
def b; 2; end
|
212
|
+
private
|
213
|
+
def a; 1; end
|
214
|
+
end
|
215
|
+
const_set(:DatasetMethods, dm)
|
216
|
+
end
|
217
|
+
@c.plugin m
|
218
|
+
@c.dataset.b.should == 2
|
219
|
+
lambda{@c.dataset.a}.should raise_error(NoMethodError)
|
220
|
+
@c.dataset.send(:a).should == 1
|
221
|
+
@c.b.should == 2
|
222
|
+
lambda{@c.a}.should raise_error(NoMethodError)
|
223
|
+
lambda{@c.send(:a)}.should raise_error(NoMethodError)
|
224
|
+
end
|
225
|
+
|
226
|
+
it "should not raise an error if the DatasetMethod module has no public instance methods" do
|
227
|
+
m = Module.new do
|
228
|
+
dm = Module.new do
|
229
|
+
private
|
230
|
+
def a; 1; end
|
231
|
+
end
|
232
|
+
const_set(:DatasetMethods, dm)
|
233
|
+
end
|
234
|
+
lambda{@c.plugin m}.should_not raise_error
|
235
|
+
end
|
236
|
+
end
|
@@ -0,0 +1,1500 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "spec_helper")
|
2
|
+
|
3
|
+
describe "Model#save server use" do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@c = Class.new(Sequel::Model(:items)) do
|
7
|
+
columns :id, :x, :y
|
8
|
+
end
|
9
|
+
@c.db = MockDatabase.new
|
10
|
+
db2 = @db2 = MockDatabase.new
|
11
|
+
@c.class_eval do
|
12
|
+
define_method(:after_save) do
|
13
|
+
model.db = db2
|
14
|
+
ds = model.dataset
|
15
|
+
def ds.fetch_rows(sql)
|
16
|
+
yield @db.execute(sql, @opts[:server])
|
17
|
+
end
|
18
|
+
@this = nil
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should use the :default server if the model doesn't have one already specified" do
|
24
|
+
@c.db.should_receive(:execute).with("INSERT INTO items (x) VALUES (1)").and_return(10)
|
25
|
+
@db2.should_receive(:execute).with('SELECT * FROM items WHERE (id = 10) LIMIT 1', :default).and_return(:x=>1, :id=>10)
|
26
|
+
@c.new(:x=>1).save
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should use the model's server if the model has one already specified" do
|
30
|
+
@c.dataset = @c.dataset.server(:blah)
|
31
|
+
@c.db.should_receive(:execute).with("INSERT INTO items (x) VALUES (1)").and_return(10)
|
32
|
+
@db2.should_receive(:execute).with('SELECT * FROM items WHERE (id = 10) LIMIT 1', :blah).and_return(:x=>1, :id=>10)
|
33
|
+
@c.new(:x=>1).save
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "Model#save" do
|
38
|
+
before do
|
39
|
+
@c = Class.new(Sequel::Model(:items)) do
|
40
|
+
columns :id, :x, :y
|
41
|
+
end
|
42
|
+
@c.dataset.meta_def(:insert){|h| super(h); 1}
|
43
|
+
MODEL_DB.reset
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should insert a record for a new model instance" do
|
47
|
+
o = @c.new(:x => 1)
|
48
|
+
o.save
|
49
|
+
MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (1)",
|
50
|
+
"SELECT * FROM items WHERE (id = 1) LIMIT 1"]
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should use dataset's insert_select method if present" do
|
54
|
+
ds = @c.dataset = @c.dataset.clone
|
55
|
+
def ds.insert_select(hash)
|
56
|
+
execute("INSERT INTO items (y) VALUES (2)")
|
57
|
+
{:y=>2}
|
58
|
+
end
|
59
|
+
o = @c.new(:x => 1)
|
60
|
+
o.save
|
61
|
+
|
62
|
+
o.values.should == {:y=>2}
|
63
|
+
MODEL_DB.sqls.should == ["INSERT INTO items (y) VALUES (2)"]
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should use value returned by insert as the primary key" do
|
67
|
+
@c.dataset.meta_def(:insert){|h| super(h); 13}
|
68
|
+
o = @c.new(:x => 11)
|
69
|
+
o.save
|
70
|
+
MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (11)",
|
71
|
+
"SELECT * FROM items WHERE (id = 13) LIMIT 1"]
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should work correctly for inserting a record without a primary key" do
|
75
|
+
@c.dataset.meta_def(:insert){|h| super(h); 13}
|
76
|
+
@c.no_primary_key
|
77
|
+
o = @c.new(:x => 11)
|
78
|
+
o.save
|
79
|
+
MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (11)"]
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should set the autoincrementing_primary_key value to the value returned by insert" do
|
83
|
+
@c.dataset.meta_def(:insert){|h| super(h); 13}
|
84
|
+
@c.unrestrict_primary_key
|
85
|
+
@c.set_primary_key [:x, :y]
|
86
|
+
o = @c.new(:x => 11)
|
87
|
+
o.meta_def(:autoincrementing_primary_key){:y}
|
88
|
+
o.save
|
89
|
+
MODEL_DB.sqls.length.should == 2
|
90
|
+
MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (11)"
|
91
|
+
MODEL_DB.sqls.last.should =~ %r{SELECT \* FROM items WHERE \(\([xy] = 1[13]\) AND \([xy] = 1[13]\)\) LIMIT 1}
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should update a record for an existing model instance" do
|
95
|
+
o = @c.load(:id => 3, :x => 1)
|
96
|
+
o.save
|
97
|
+
MODEL_DB.sqls.should == ["UPDATE items SET x = 1 WHERE (id = 3)"]
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should raise a NoExistingObject exception if the dataset update call doesn't return 1, unless require_modification is false" do
|
101
|
+
o = @c.load(:id => 3, :x => 1)
|
102
|
+
o.this.meta_def(:update){|*a| 0}
|
103
|
+
proc{o.save}.should raise_error(Sequel::NoExistingObject)
|
104
|
+
o.this.meta_def(:update){|*a| 2}
|
105
|
+
proc{o.save}.should raise_error(Sequel::NoExistingObject)
|
106
|
+
o.this.meta_def(:update){|*a| 1}
|
107
|
+
proc{o.save}.should_not raise_error
|
108
|
+
|
109
|
+
o.require_modification = false
|
110
|
+
o.this.meta_def(:update){|*a| 0}
|
111
|
+
proc{o.save}.should_not raise_error
|
112
|
+
o.this.meta_def(:update){|*a| 2}
|
113
|
+
proc{o.save}.should_not raise_error
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should update only the given columns if given" do
|
117
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
118
|
+
o.save(:y)
|
119
|
+
MODEL_DB.sqls.first.should == "UPDATE items SET y = NULL WHERE (id = 3)"
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should mark saved columns as not changed" do
|
123
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
124
|
+
o[:y] = 4
|
125
|
+
o.changed_columns.should == [:y]
|
126
|
+
o.save(:x)
|
127
|
+
o.changed_columns.should == [:y]
|
128
|
+
o.save(:y)
|
129
|
+
o.changed_columns.should == []
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should mark all columns as not changed if this is a new record" do
|
133
|
+
o = @c.new(:x => 1, :y => nil)
|
134
|
+
o.x = 4
|
135
|
+
o.changed_columns.should == [:x]
|
136
|
+
o.save
|
137
|
+
o.changed_columns.should == []
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should mark all columns as not changed if this is a new record and insert_select was used" do
|
141
|
+
@c.dataset.meta_def(:insert_select){|h| h.merge(:id=>1)}
|
142
|
+
o = @c.new(:x => 1, :y => nil)
|
143
|
+
o.x = 4
|
144
|
+
o.changed_columns.should == [:x]
|
145
|
+
o.save
|
146
|
+
o.changed_columns.should == []
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should store previous value of @new in @was_new and as well as the hash used for updating in @columns_updated until after hooks finish running" do
|
150
|
+
res = nil
|
151
|
+
@c.send(:define_method, :after_save){ res = [@columns_updated, @was_new]}
|
152
|
+
o = @c.new(:x => 1, :y => nil)
|
153
|
+
o[:x] = 2
|
154
|
+
o.save
|
155
|
+
res.should == [nil, true]
|
156
|
+
o.after_save
|
157
|
+
res.should == [nil, nil]
|
158
|
+
|
159
|
+
res = nil
|
160
|
+
o = @c.load(:id => 23,:x => 1, :y => nil)
|
161
|
+
o[:x] = 2
|
162
|
+
o.save
|
163
|
+
res.should == [{:x => 2, :y => nil}, nil]
|
164
|
+
o.after_save
|
165
|
+
res.should == [nil, nil]
|
166
|
+
|
167
|
+
res = nil
|
168
|
+
o = @c.load(:id => 23,:x => 2, :y => nil)
|
169
|
+
o[:x] = 2
|
170
|
+
o[:y] = 22
|
171
|
+
o.save(:x)
|
172
|
+
res.should == [{:x=>2},nil]
|
173
|
+
o.after_save
|
174
|
+
res.should == [nil, nil]
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should use Model's use_transactions setting by default" do
|
178
|
+
@c.use_transactions = true
|
179
|
+
@c.load(:id => 3, :x => 1, :y => nil).save(:y)
|
180
|
+
MODEL_DB.sqls.should == ["BEGIN", "UPDATE items SET y = NULL WHERE (id = 3)", "COMMIT"]
|
181
|
+
MODEL_DB.reset
|
182
|
+
@c.use_transactions = false
|
183
|
+
@c.load(:id => 3, :x => 1, :y => nil).save(:y)
|
184
|
+
MODEL_DB.sqls.should == ["UPDATE items SET y = NULL WHERE (id = 3)"]
|
185
|
+
MODEL_DB.reset
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should inherit Model's use_transactions setting" do
|
189
|
+
@c.use_transactions = true
|
190
|
+
Class.new(@c).load(:id => 3, :x => 1, :y => nil).save(:y)
|
191
|
+
MODEL_DB.sqls.should == ["BEGIN", "UPDATE items SET y = NULL WHERE (id = 3)", "COMMIT"]
|
192
|
+
MODEL_DB.reset
|
193
|
+
@c.use_transactions = false
|
194
|
+
Class.new(@c).load(:id => 3, :x => 1, :y => nil).save(:y)
|
195
|
+
MODEL_DB.sqls.should == ["UPDATE items SET y = NULL WHERE (id = 3)"]
|
196
|
+
MODEL_DB.reset
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should use object's use_transactions setting" do
|
200
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
201
|
+
o.use_transactions = false
|
202
|
+
@c.use_transactions = true
|
203
|
+
o.save(:y)
|
204
|
+
MODEL_DB.sqls.should == ["UPDATE items SET y = NULL WHERE (id = 3)"]
|
205
|
+
MODEL_DB.reset
|
206
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
207
|
+
o.use_transactions = true
|
208
|
+
@c.use_transactions = false
|
209
|
+
o.save(:y)
|
210
|
+
MODEL_DB.sqls.should == ["BEGIN", "UPDATE items SET y = NULL WHERE (id = 3)", "COMMIT"]
|
211
|
+
MODEL_DB.reset
|
212
|
+
end
|
213
|
+
|
214
|
+
it "should use :transaction option if given" do
|
215
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
216
|
+
o.use_transactions = true
|
217
|
+
o.save(:y, :transaction=>false)
|
218
|
+
MODEL_DB.sqls.should == ["UPDATE items SET y = NULL WHERE (id = 3)"]
|
219
|
+
MODEL_DB.reset
|
220
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
221
|
+
o.use_transactions = false
|
222
|
+
o.save(:y, :transaction=>true)
|
223
|
+
MODEL_DB.sqls.should == ["BEGIN", "UPDATE items SET y = NULL WHERE (id = 3)", "COMMIT"]
|
224
|
+
MODEL_DB.reset
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should rollback if before_save returns false and raise_on_save_failure = true" do
|
228
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
229
|
+
o.use_transactions = true
|
230
|
+
o.raise_on_save_failure = true
|
231
|
+
def o.before_save
|
232
|
+
false
|
233
|
+
end
|
234
|
+
proc { o.save(:y) }.should raise_error(Sequel::BeforeHookFailed)
|
235
|
+
MODEL_DB.sqls.should == ["BEGIN", "ROLLBACK"]
|
236
|
+
MODEL_DB.reset
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should not rollback outer transactions if before_save returns false and raise_on_save_failure = false" do
|
240
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
241
|
+
o.use_transactions = true
|
242
|
+
o.raise_on_save_failure = false
|
243
|
+
def o.before_save
|
244
|
+
false
|
245
|
+
end
|
246
|
+
MODEL_DB.transaction do
|
247
|
+
o.save(:y).should == nil
|
248
|
+
MODEL_DB.run "BLAH"
|
249
|
+
end
|
250
|
+
MODEL_DB.sqls.should == ["BEGIN", "BLAH", "COMMIT"]
|
251
|
+
MODEL_DB.reset
|
252
|
+
end
|
253
|
+
|
254
|
+
it "should rollback if before_save returns false and raise_on_save_failure = false" do
|
255
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
256
|
+
o.use_transactions = true
|
257
|
+
o.raise_on_save_failure = false
|
258
|
+
def o.before_save
|
259
|
+
false
|
260
|
+
end
|
261
|
+
o.save(:y).should == nil
|
262
|
+
MODEL_DB.sqls.should == ["BEGIN", "ROLLBACK"]
|
263
|
+
MODEL_DB.reset
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should not rollback if before_save throws Rollback and use_transactions = false" do
|
267
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
268
|
+
o.use_transactions = false
|
269
|
+
def o.before_save
|
270
|
+
raise Sequel::Rollback
|
271
|
+
end
|
272
|
+
proc { o.save(:y) }.should raise_error(Sequel::Rollback)
|
273
|
+
MODEL_DB.sqls.should == []
|
274
|
+
MODEL_DB.reset
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
describe "Model#marshallable" do
|
279
|
+
before do
|
280
|
+
class ::Album < Sequel::Model
|
281
|
+
columns :id, :x
|
282
|
+
end
|
283
|
+
Album.dataset.meta_def(:insert){|h| super(h); 1}
|
284
|
+
end
|
285
|
+
after do
|
286
|
+
Object.send(:remove_const, :Album)
|
287
|
+
end
|
288
|
+
|
289
|
+
it "should make an object marshallable" do
|
290
|
+
i = Album.new(:x=>2)
|
291
|
+
s = nil
|
292
|
+
i2 = nil
|
293
|
+
i.marshallable!
|
294
|
+
proc{s = Marshal.dump(i)}.should_not raise_error
|
295
|
+
proc{i2 = Marshal.load(s)}.should_not raise_error
|
296
|
+
i2.should == i
|
297
|
+
|
298
|
+
i.save
|
299
|
+
i.marshallable!
|
300
|
+
proc{s = Marshal.dump(i)}.should_not raise_error
|
301
|
+
proc{i2 = Marshal.load(s)}.should_not raise_error
|
302
|
+
i2.should == i
|
303
|
+
|
304
|
+
i.save
|
305
|
+
i.marshallable!
|
306
|
+
proc{s = Marshal.dump(i)}.should_not raise_error
|
307
|
+
proc{i2 = Marshal.load(s)}.should_not raise_error
|
308
|
+
i2.should == i
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
describe "Model#modified[!?]" do
|
313
|
+
before do
|
314
|
+
@c = Class.new(Sequel::Model(:items))
|
315
|
+
@c.class_eval do
|
316
|
+
columns :id, :x
|
317
|
+
@db_schema = {:x => {:type => :integer}}
|
318
|
+
end
|
319
|
+
MODEL_DB.reset
|
320
|
+
end
|
321
|
+
|
322
|
+
it "should be true if the object is new" do
|
323
|
+
@c.new.modified?.should == true
|
324
|
+
end
|
325
|
+
|
326
|
+
it "should be false if the object has not been modified" do
|
327
|
+
@c.load(:id=>1).modified?.should == false
|
328
|
+
end
|
329
|
+
|
330
|
+
it "should be true if the object has been modified" do
|
331
|
+
o = @c.load(:id=>1, :x=>2)
|
332
|
+
o.x = 3
|
333
|
+
o.modified?.should == true
|
334
|
+
end
|
335
|
+
|
336
|
+
it "should be true if the object is marked modified!" do
|
337
|
+
o = @c.load(:id=>1, :x=>2)
|
338
|
+
o.modified!
|
339
|
+
o.modified?.should == true
|
340
|
+
end
|
341
|
+
|
342
|
+
it "should be false if the object is marked modified! after saving until modified! again" do
|
343
|
+
o = @c.load(:id=>1, :x=>2)
|
344
|
+
o.modified!
|
345
|
+
o.save
|
346
|
+
o.modified?.should == false
|
347
|
+
o.modified!
|
348
|
+
o.modified?.should == true
|
349
|
+
end
|
350
|
+
|
351
|
+
it "should be false if a column value is set that is the same as the current value after typecasting" do
|
352
|
+
o = @c.load(:id=>1, :x=>2)
|
353
|
+
o.x = '2'
|
354
|
+
o.modified?.should == false
|
355
|
+
end
|
356
|
+
|
357
|
+
it "should be true if a column value is set that is the different as the current value after typecasting" do
|
358
|
+
o = @c.load(:id=>1, :x=>'2')
|
359
|
+
o.x = '2'
|
360
|
+
o.modified?.should == true
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
describe "Model#save_changes" do
|
365
|
+
|
366
|
+
before do
|
367
|
+
@c = Class.new(Sequel::Model(:items)) do
|
368
|
+
unrestrict_primary_key
|
369
|
+
columns :id, :x, :y
|
370
|
+
end
|
371
|
+
MODEL_DB.reset
|
372
|
+
end
|
373
|
+
|
374
|
+
it "should always save if the object is new" do
|
375
|
+
o = @c.new(:x => 1)
|
376
|
+
o.save_changes
|
377
|
+
MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
|
378
|
+
end
|
379
|
+
|
380
|
+
it "should take options passed to save" do
|
381
|
+
o = @c.new(:x => 1)
|
382
|
+
def o.valid?; false; end
|
383
|
+
proc{o.save_changes}.should raise_error(Sequel::Error)
|
384
|
+
MODEL_DB.sqls.should == []
|
385
|
+
o.save_changes(:validate=>false)
|
386
|
+
MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
|
387
|
+
end
|
388
|
+
|
389
|
+
it "should do nothing if no changed columns" do
|
390
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
391
|
+
o.save_changes
|
392
|
+
MODEL_DB.sqls.should == []
|
393
|
+
end
|
394
|
+
|
395
|
+
it "should do nothing if modified? is false" do
|
396
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
397
|
+
def o.modified?; false; end
|
398
|
+
o.save_changes
|
399
|
+
MODEL_DB.sqls.should == []
|
400
|
+
end
|
401
|
+
|
402
|
+
it "should update only changed columns" do
|
403
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
404
|
+
o.x = 2
|
405
|
+
|
406
|
+
o.save_changes
|
407
|
+
MODEL_DB.sqls.should == ["UPDATE items SET x = 2 WHERE (id = 3)"]
|
408
|
+
o.save_changes
|
409
|
+
o.save_changes
|
410
|
+
MODEL_DB.sqls.should == ["UPDATE items SET x = 2 WHERE (id = 3)"]
|
411
|
+
MODEL_DB.reset
|
412
|
+
|
413
|
+
o.y = 4
|
414
|
+
o.save_changes
|
415
|
+
MODEL_DB.sqls.should == ["UPDATE items SET y = 4 WHERE (id = 3)"]
|
416
|
+
o.save_changes
|
417
|
+
o.save_changes
|
418
|
+
MODEL_DB.sqls.should == ["UPDATE items SET y = 4 WHERE (id = 3)"]
|
419
|
+
end
|
420
|
+
|
421
|
+
it "should not consider columns changed if the values did not change" do
|
422
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
423
|
+
o.x = 1
|
424
|
+
|
425
|
+
o.save_changes
|
426
|
+
MODEL_DB.sqls.should == []
|
427
|
+
o.x = 3
|
428
|
+
o.save_changes
|
429
|
+
MODEL_DB.sqls.should == ["UPDATE items SET x = 3 WHERE (id = 3)"]
|
430
|
+
MODEL_DB.reset
|
431
|
+
|
432
|
+
o[:y] = nil
|
433
|
+
o.save_changes
|
434
|
+
MODEL_DB.sqls.should == []
|
435
|
+
o[:y] = 4
|
436
|
+
o.save_changes
|
437
|
+
MODEL_DB.sqls.should == ["UPDATE items SET y = 4 WHERE (id = 3)"]
|
438
|
+
end
|
439
|
+
|
440
|
+
it "should clear changed_columns" do
|
441
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
442
|
+
o.x = 4
|
443
|
+
o.changed_columns.should == [:x]
|
444
|
+
o.save_changes
|
445
|
+
o.changed_columns.should == []
|
446
|
+
end
|
447
|
+
|
448
|
+
it "should update columns changed in a before_update hook" do
|
449
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
450
|
+
@c.send(:define_method, :before_update){self.x += 1}
|
451
|
+
o.save_changes
|
452
|
+
MODEL_DB.sqls.should == []
|
453
|
+
o.x = 2
|
454
|
+
o.save_changes
|
455
|
+
MODEL_DB.sqls.should == ["UPDATE items SET x = 3 WHERE (id = 3)"]
|
456
|
+
MODEL_DB.reset
|
457
|
+
o.save_changes
|
458
|
+
MODEL_DB.sqls.should == []
|
459
|
+
o.x = 4
|
460
|
+
o.save_changes
|
461
|
+
MODEL_DB.sqls.should == ["UPDATE items SET x = 5 WHERE (id = 3)"]
|
462
|
+
MODEL_DB.reset
|
463
|
+
end
|
464
|
+
|
465
|
+
it "should update columns changed in a before_save hook" do
|
466
|
+
o = @c.load(:id => 3, :x => 1, :y => nil)
|
467
|
+
@c.send(:define_method, :before_update){self.x += 1}
|
468
|
+
o.save_changes
|
469
|
+
MODEL_DB.sqls.should == []
|
470
|
+
o.x = 2
|
471
|
+
o.save_changes
|
472
|
+
MODEL_DB.sqls.should == ["UPDATE items SET x = 3 WHERE (id = 3)"]
|
473
|
+
MODEL_DB.reset
|
474
|
+
o.save_changes
|
475
|
+
MODEL_DB.sqls.should == []
|
476
|
+
o.x = 4
|
477
|
+
o.save_changes
|
478
|
+
MODEL_DB.sqls.should == ["UPDATE items SET x = 5 WHERE (id = 3)"]
|
479
|
+
MODEL_DB.reset
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
describe "Model#new?" do
|
484
|
+
|
485
|
+
before(:each) do
|
486
|
+
MODEL_DB.reset
|
487
|
+
|
488
|
+
@c = Class.new(Sequel::Model(:items)) do
|
489
|
+
unrestrict_primary_key
|
490
|
+
columns :x
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
it "should be true for a new instance" do
|
495
|
+
n = @c.new(:x => 1)
|
496
|
+
n.should be_new
|
497
|
+
end
|
498
|
+
|
499
|
+
it "should be false after saving" do
|
500
|
+
n = @c.new(:x => 1)
|
501
|
+
n.save
|
502
|
+
n.should_not be_new
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
describe Sequel::Model, "w/ primary key" do
|
507
|
+
|
508
|
+
it "should default to ':id'" do
|
509
|
+
model_a = Class.new Sequel::Model
|
510
|
+
model_a.primary_key.should be_equal(:id)
|
511
|
+
end
|
512
|
+
|
513
|
+
it "should be changed through 'set_primary_key'" do
|
514
|
+
model_a = Class.new(Sequel::Model) { set_primary_key :a }
|
515
|
+
model_a.primary_key.should be_equal(:a)
|
516
|
+
end
|
517
|
+
|
518
|
+
it "should support multi argument composite keys" do
|
519
|
+
model_a = Class.new(Sequel::Model) { set_primary_key :a, :b }
|
520
|
+
model_a.primary_key.should be_eql([:a, :b])
|
521
|
+
end
|
522
|
+
|
523
|
+
it "should accept single argument composite keys" do
|
524
|
+
model_a = Class.new(Sequel::Model) { set_primary_key [:a, :b] }
|
525
|
+
model_a.primary_key.should be_eql([:a, :b])
|
526
|
+
end
|
527
|
+
|
528
|
+
end
|
529
|
+
|
530
|
+
describe Sequel::Model, "w/o primary key" do
|
531
|
+
it "should return nil for primary key" do
|
532
|
+
Class.new(Sequel::Model) { no_primary_key }.primary_key.should be_nil
|
533
|
+
end
|
534
|
+
|
535
|
+
it "should raise a Sequel::Error on 'this'" do
|
536
|
+
instance = Class.new(Sequel::Model) { no_primary_key }.new
|
537
|
+
proc { instance.this }.should raise_error(Sequel::Error)
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
describe Sequel::Model, "with this" do
|
542
|
+
|
543
|
+
before { @example = Class.new Sequel::Model(:examples); @example.columns :id, :a, :x, :y }
|
544
|
+
|
545
|
+
it "should return a dataset identifying the record" do
|
546
|
+
instance = @example.load :id => 3
|
547
|
+
instance.this.sql.should be_eql("SELECT * FROM examples WHERE (id = 3) LIMIT 1")
|
548
|
+
end
|
549
|
+
|
550
|
+
it "should support arbitary primary keys" do
|
551
|
+
@example.set_primary_key :a
|
552
|
+
|
553
|
+
instance = @example.load :a => 3
|
554
|
+
instance.this.sql.should be_eql("SELECT * FROM examples WHERE (a = 3) LIMIT 1")
|
555
|
+
end
|
556
|
+
|
557
|
+
it "should support composite primary keys" do
|
558
|
+
@example.set_primary_key :x, :y
|
559
|
+
instance = @example.load :x => 4, :y => 5
|
560
|
+
|
561
|
+
parts = [
|
562
|
+
'SELECT * FROM examples WHERE %s LIMIT 1',
|
563
|
+
'((x = 4) AND (y = 5))',
|
564
|
+
'((y = 5) AND (x = 4))'
|
565
|
+
].map { |expr| Regexp.escape expr }
|
566
|
+
regexp = Regexp.new parts.first % "(?:#{parts[1]}|#{parts[2]})"
|
567
|
+
|
568
|
+
instance.this.sql.should match(regexp)
|
569
|
+
end
|
570
|
+
|
571
|
+
end
|
572
|
+
|
573
|
+
describe "Model#pk" do
|
574
|
+
before(:each) do
|
575
|
+
@m = Class.new(Sequel::Model)
|
576
|
+
@m.columns :id, :x, :y
|
577
|
+
end
|
578
|
+
|
579
|
+
it "should be default return the value of the :id column" do
|
580
|
+
m = @m.load(:id => 111, :x => 2, :y => 3)
|
581
|
+
m.pk.should == 111
|
582
|
+
end
|
583
|
+
|
584
|
+
it "should be return the primary key value for custom primary key" do
|
585
|
+
@m.set_primary_key :x
|
586
|
+
m = @m.load(:id => 111, :x => 2, :y => 3)
|
587
|
+
m.pk.should == 2
|
588
|
+
end
|
589
|
+
|
590
|
+
it "should be return the primary key value for composite primary key" do
|
591
|
+
@m.set_primary_key [:y, :x]
|
592
|
+
m = @m.load(:id => 111, :x => 2, :y => 3)
|
593
|
+
m.pk.should == [3, 2]
|
594
|
+
end
|
595
|
+
|
596
|
+
it "should raise if no primary key" do
|
597
|
+
@m.set_primary_key nil
|
598
|
+
m = @m.new(:id => 111, :x => 2, :y => 3)
|
599
|
+
proc {m.pk}.should raise_error(Sequel::Error)
|
600
|
+
|
601
|
+
@m.no_primary_key
|
602
|
+
m = @m.new(:id => 111, :x => 2, :y => 3)
|
603
|
+
proc {m.pk}.should raise_error(Sequel::Error)
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
describe "Model#pk_hash" do
|
608
|
+
before(:each) do
|
609
|
+
@m = Class.new(Sequel::Model)
|
610
|
+
@m.columns :id, :x, :y
|
611
|
+
end
|
612
|
+
|
613
|
+
it "should be default return the value of the :id column" do
|
614
|
+
m = @m.load(:id => 111, :x => 2, :y => 3)
|
615
|
+
m.pk_hash.should == {:id => 111}
|
616
|
+
end
|
617
|
+
|
618
|
+
it "should be return the primary key value for custom primary key" do
|
619
|
+
@m.set_primary_key :x
|
620
|
+
m = @m.load(:id => 111, :x => 2, :y => 3)
|
621
|
+
m.pk_hash.should == {:x => 2}
|
622
|
+
end
|
623
|
+
|
624
|
+
it "should be return the primary key value for composite primary key" do
|
625
|
+
@m.set_primary_key [:y, :x]
|
626
|
+
m = @m.load(:id => 111, :x => 2, :y => 3)
|
627
|
+
m.pk_hash.should == {:y => 3, :x => 2}
|
628
|
+
end
|
629
|
+
|
630
|
+
it "should raise if no primary key" do
|
631
|
+
@m.set_primary_key nil
|
632
|
+
m = @m.new(:id => 111, :x => 2, :y => 3)
|
633
|
+
proc {m.pk_hash}.should raise_error(Sequel::Error)
|
634
|
+
|
635
|
+
@m.no_primary_key
|
636
|
+
m = @m.new(:id => 111, :x => 2, :y => 3)
|
637
|
+
proc {m.pk_hash}.should raise_error(Sequel::Error)
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
describe Sequel::Model, "#set" do
|
642
|
+
before do
|
643
|
+
MODEL_DB.reset
|
644
|
+
|
645
|
+
@c = Class.new(Sequel::Model(:items)) do
|
646
|
+
set_primary_key :id
|
647
|
+
columns :x, :y, :id
|
648
|
+
end
|
649
|
+
@c.strict_param_setting = false
|
650
|
+
@c.instance_variable_set(:@columns, true)
|
651
|
+
@o1 = @c.new
|
652
|
+
@o2 = @c.load(:id => 5)
|
653
|
+
end
|
654
|
+
|
655
|
+
it "should filter the given params using the model columns" do
|
656
|
+
@o1.set(:x => 1, :z => 2)
|
657
|
+
@o1.values.should == {:x => 1}
|
658
|
+
MODEL_DB.sqls.should == []
|
659
|
+
|
660
|
+
@o2.set(:y => 1, :abc => 2)
|
661
|
+
@o2.values.should == {:y => 1, :id=> 5}
|
662
|
+
MODEL_DB.sqls.should == []
|
663
|
+
end
|
664
|
+
|
665
|
+
it "should work with both strings and symbols" do
|
666
|
+
@o1.set('x'=> 1, 'z'=> 2)
|
667
|
+
@o1.values.should == {:x => 1}
|
668
|
+
MODEL_DB.sqls.should == []
|
669
|
+
|
670
|
+
@o2.set('y'=> 1, 'abc'=> 2)
|
671
|
+
@o2.values.should == {:y => 1, :id=> 5}
|
672
|
+
MODEL_DB.sqls.should == []
|
673
|
+
end
|
674
|
+
|
675
|
+
it "should support virtual attributes" do
|
676
|
+
@c.send(:define_method, :blah=){|v| self.x = v}
|
677
|
+
@o1.set(:blah => 333)
|
678
|
+
@o1.values.should == {:x => 333}
|
679
|
+
MODEL_DB.sqls.should == []
|
680
|
+
@o1.set('blah'=> 334)
|
681
|
+
@o1.values.should == {:x => 334}
|
682
|
+
MODEL_DB.sqls.should == []
|
683
|
+
end
|
684
|
+
|
685
|
+
it "should not modify the primary key" do
|
686
|
+
@o1.set(:x => 1, :id => 2)
|
687
|
+
@o1.values.should == {:x => 1}
|
688
|
+
MODEL_DB.sqls.should == []
|
689
|
+
@o2.set('y'=> 1, 'id'=> 2)
|
690
|
+
@o2.values.should == {:y => 1, :id=> 5}
|
691
|
+
MODEL_DB.sqls.should == []
|
692
|
+
end
|
693
|
+
|
694
|
+
it "should return self" do
|
695
|
+
returned_value = @o1.set(:x => 1, :z => 2)
|
696
|
+
returned_value.should == @o1
|
697
|
+
MODEL_DB.sqls.should == []
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
701
|
+
describe Sequel::Model, "#update" do
|
702
|
+
before do
|
703
|
+
MODEL_DB.reset
|
704
|
+
|
705
|
+
@c = Class.new(Sequel::Model(:items)) do
|
706
|
+
set_primary_key :id
|
707
|
+
columns :x, :y, :id
|
708
|
+
end
|
709
|
+
@c.strict_param_setting = false
|
710
|
+
@c.instance_variable_set(:@columns, true)
|
711
|
+
@o1 = @c.new
|
712
|
+
@o2 = @c.load(:id => 5)
|
713
|
+
end
|
714
|
+
|
715
|
+
it "should filter the given params using the model columns" do
|
716
|
+
@o1.update(:x => 1, :z => 2)
|
717
|
+
MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
|
718
|
+
|
719
|
+
MODEL_DB.reset
|
720
|
+
@o2.update(:y => 1, :abc => 2)
|
721
|
+
MODEL_DB.sqls.first.should == "UPDATE items SET y = 1 WHERE (id = 5)"
|
722
|
+
end
|
723
|
+
|
724
|
+
it "should support virtual attributes" do
|
725
|
+
@c.send(:define_method, :blah=){|v| self.x = v}
|
726
|
+
@o1.update(:blah => 333)
|
727
|
+
MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (333)"
|
728
|
+
end
|
729
|
+
|
730
|
+
it "should not modify the primary key" do
|
731
|
+
@o1.update(:x => 1, :id => 2)
|
732
|
+
MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
|
733
|
+
MODEL_DB.reset
|
734
|
+
@o2.update('y'=> 1, 'id'=> 2)
|
735
|
+
@o2.values.should == {:y => 1, :id=> 5}
|
736
|
+
MODEL_DB.sqls.first.should == "UPDATE items SET y = 1 WHERE (id = 5)"
|
737
|
+
end
|
738
|
+
end
|
739
|
+
|
740
|
+
describe Sequel::Model, "#(set|update)_(all|except|only)" do
|
741
|
+
before do
|
742
|
+
MODEL_DB.reset
|
743
|
+
|
744
|
+
@c = Class.new(Sequel::Model(:items)) do
|
745
|
+
set_primary_key :id
|
746
|
+
columns :x, :y, :z, :id
|
747
|
+
set_allowed_columns :x
|
748
|
+
set_restricted_columns :y
|
749
|
+
end
|
750
|
+
@c.strict_param_setting = false
|
751
|
+
@c.instance_variable_set(:@columns, true)
|
752
|
+
@o1 = @c.new
|
753
|
+
end
|
754
|
+
|
755
|
+
it "#set_all should set all attributes" do
|
756
|
+
@o1.set_all(:x => 1, :y => 2, :z=>3, :id=>4)
|
757
|
+
@o1.values.should == {:x => 1, :y => 2, :z=>3}
|
758
|
+
end
|
759
|
+
|
760
|
+
it "#set_only should only set given attributes" do
|
761
|
+
@o1.set_only({:x => 1, :y => 2, :z=>3, :id=>4}, [:x, :y])
|
762
|
+
@o1.values.should == {:x => 1, :y => 2}
|
763
|
+
@o1.set_only({:x => 4, :y => 5, :z=>6, :id=>7}, :x, :y)
|
764
|
+
@o1.values.should == {:x => 4, :y => 5}
|
765
|
+
end
|
766
|
+
|
767
|
+
it "#set_except should not set given attributes" do
|
768
|
+
@o1.set_except({:x => 1, :y => 2, :z=>3, :id=>4}, [:y, :z])
|
769
|
+
@o1.values.should == {:x => 1}
|
770
|
+
@o1.set_except({:x => 4, :y => 2, :z=>3, :id=>4}, :y, :z)
|
771
|
+
@o1.values.should == {:x => 4}
|
772
|
+
end
|
773
|
+
|
774
|
+
it "#update_all should update all attributes" do
|
775
|
+
@c.new.update_all(:x => 1, :id=>4)
|
776
|
+
MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
|
777
|
+
MODEL_DB.reset
|
778
|
+
@c.new.update_all(:y => 1, :id=>4)
|
779
|
+
MODEL_DB.sqls.first.should == "INSERT INTO items (y) VALUES (1)"
|
780
|
+
MODEL_DB.reset
|
781
|
+
@c.new.update_all(:z => 1, :id=>4)
|
782
|
+
MODEL_DB.sqls.first.should == "INSERT INTO items (z) VALUES (1)"
|
783
|
+
end
|
784
|
+
|
785
|
+
it "#update_only should only update given attributes" do
|
786
|
+
@o1.update_only({:x => 1, :y => 2, :z=>3, :id=>4}, [:x])
|
787
|
+
MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
|
788
|
+
MODEL_DB.reset
|
789
|
+
@c.new.update_only({:x => 1, :y => 2, :z=>3, :id=>4}, :x)
|
790
|
+
MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
|
791
|
+
end
|
792
|
+
|
793
|
+
it "#update_except should not update given attributes" do
|
794
|
+
@o1.update_except({:x => 1, :y => 2, :z=>3, :id=>4}, [:y, :z])
|
795
|
+
MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
|
796
|
+
MODEL_DB.reset
|
797
|
+
@c.new.update_except({:x => 1, :y => 2, :z=>3, :id=>4}, :y, :z)
|
798
|
+
MODEL_DB.sqls.first.should == "INSERT INTO items (x) VALUES (1)"
|
799
|
+
end
|
800
|
+
end
|
801
|
+
|
802
|
+
describe Sequel::Model, "#destroy" do
|
803
|
+
before do
|
804
|
+
MODEL_DB.reset
|
805
|
+
@model = Class.new(Sequel::Model(:items))
|
806
|
+
@model.columns :id
|
807
|
+
@model.dataset.meta_def(:delete){MODEL_DB.execute delete_sql;1}
|
808
|
+
|
809
|
+
@instance = @model.load(:id => 1234)
|
810
|
+
end
|
811
|
+
|
812
|
+
it "should return self" do
|
813
|
+
@model.send(:define_method, :after_destroy){3}
|
814
|
+
@instance.destroy.should == @instance
|
815
|
+
end
|
816
|
+
|
817
|
+
it "should raise a NoExistingObject exception if the dataset delete call doesn't return 1" do
|
818
|
+
@instance.this.meta_def(:delete){|*a| 0}
|
819
|
+
proc{@instance.delete}.should raise_error(Sequel::NoExistingObject)
|
820
|
+
@instance.this.meta_def(:delete){|*a| 2}
|
821
|
+
proc{@instance.delete}.should raise_error(Sequel::NoExistingObject)
|
822
|
+
@instance.this.meta_def(:delete){|*a| 1}
|
823
|
+
proc{@instance.delete}.should_not raise_error
|
824
|
+
|
825
|
+
@instance.require_modification = false
|
826
|
+
@instance.this.meta_def(:delete){|*a| 0}
|
827
|
+
proc{@instance.delete}.should_not raise_error
|
828
|
+
@instance.this.meta_def(:delete){|*a| 2}
|
829
|
+
proc{@instance.delete}.should_not raise_error
|
830
|
+
end
|
831
|
+
|
832
|
+
it "should run within a transaction if use_transactions is true" do
|
833
|
+
@instance.use_transactions = true
|
834
|
+
@model.db.should_receive(:transaction)
|
835
|
+
@instance.destroy
|
836
|
+
end
|
837
|
+
|
838
|
+
it "should not run within a transaction if use_transactions is false" do
|
839
|
+
@instance.use_transactions = false
|
840
|
+
@model.db.should_not_receive(:transaction)
|
841
|
+
@instance.destroy
|
842
|
+
end
|
843
|
+
|
844
|
+
it "should run within a transaction if :transaction option is true" do
|
845
|
+
@instance.use_transactions = false
|
846
|
+
@model.db.should_receive(:transaction)
|
847
|
+
@instance.destroy(:transaction => true)
|
848
|
+
end
|
849
|
+
|
850
|
+
it "should not run within a transaction if :transaction option is false" do
|
851
|
+
@instance.use_transactions = true
|
852
|
+
@model.db.should_not_receive(:transaction)
|
853
|
+
@instance.destroy(:transaction => false)
|
854
|
+
end
|
855
|
+
|
856
|
+
it "should run before_destroy and after_destroy hooks" do
|
857
|
+
@model.send(:define_method, :before_destroy){MODEL_DB.execute('before blah')}
|
858
|
+
@model.send(:define_method, :after_destroy){MODEL_DB.execute('after blah')}
|
859
|
+
@instance.destroy
|
860
|
+
|
861
|
+
MODEL_DB.sqls.should == [
|
862
|
+
"before blah",
|
863
|
+
"DELETE FROM items WHERE (id = 1234)",
|
864
|
+
"after blah"
|
865
|
+
]
|
866
|
+
end
|
867
|
+
end
|
868
|
+
|
869
|
+
describe Sequel::Model, "#exists?" do
|
870
|
+
before(:each) do
|
871
|
+
@model = Class.new(Sequel::Model(:items))
|
872
|
+
@m = @model.new
|
873
|
+
end
|
874
|
+
|
875
|
+
it "should returns true when #this.count > 0" do
|
876
|
+
@m.this.meta_def(:count) {1}
|
877
|
+
@m.exists?.should be_true
|
878
|
+
end
|
879
|
+
|
880
|
+
it "should return false when #this.count == 0" do
|
881
|
+
@m.this.meta_def(:count) {0}
|
882
|
+
@m.exists?.should be_false
|
883
|
+
end
|
884
|
+
end
|
885
|
+
|
886
|
+
describe Sequel::Model, "#each" do
|
887
|
+
before do
|
888
|
+
@model = Class.new(Sequel::Model(:items))
|
889
|
+
@model.columns :a, :b, :id
|
890
|
+
@m = @model.load(:a => 1, :b => 2, :id => 4444)
|
891
|
+
end
|
892
|
+
|
893
|
+
specify "should iterate over the values" do
|
894
|
+
h = {}
|
895
|
+
@m.each {|k, v| h[k] = v}
|
896
|
+
h.should == {:a => 1, :b => 2, :id => 4444}
|
897
|
+
end
|
898
|
+
end
|
899
|
+
|
900
|
+
describe Sequel::Model, "#keys" do
|
901
|
+
before do
|
902
|
+
@model = Class.new(Sequel::Model(:items))
|
903
|
+
@model.columns :a, :b, :id
|
904
|
+
@m = @model.load(:a => 1, :b => 2, :id => 4444)
|
905
|
+
end
|
906
|
+
|
907
|
+
specify "should return the value keys" do
|
908
|
+
@m.keys.size.should == 3
|
909
|
+
@m.keys.should include(:a, :b, :id)
|
910
|
+
|
911
|
+
@m = @model.new()
|
912
|
+
@m.keys.should == []
|
913
|
+
end
|
914
|
+
end
|
915
|
+
|
916
|
+
describe Sequel::Model, "#==" do
|
917
|
+
specify "should compare instances by values" do
|
918
|
+
z = Class.new(Sequel::Model)
|
919
|
+
z.columns :id, :x
|
920
|
+
a = z.load(:id => 1, :x => 3)
|
921
|
+
b = z.load(:id => 1, :x => 4)
|
922
|
+
c = z.load(:id => 1, :x => 3)
|
923
|
+
|
924
|
+
a.should_not == b
|
925
|
+
a.should == c
|
926
|
+
b.should_not == c
|
927
|
+
end
|
928
|
+
|
929
|
+
specify "should be aliased to #eql?" do
|
930
|
+
z = Class.new(Sequel::Model)
|
931
|
+
z.columns :id, :x
|
932
|
+
a = z.load(:id => 1, :x => 3)
|
933
|
+
b = z.load(:id => 1, :x => 4)
|
934
|
+
c = z.load(:id => 1, :x => 3)
|
935
|
+
|
936
|
+
a.eql?(b).should == false
|
937
|
+
a.eql?(c).should == true
|
938
|
+
b.eql?(c).should == false
|
939
|
+
end
|
940
|
+
end
|
941
|
+
|
942
|
+
describe Sequel::Model, "#===" do
|
943
|
+
specify "should compare instances by class and pk if pk is not nil" do
|
944
|
+
z = Class.new(Sequel::Model)
|
945
|
+
z.columns :id, :x
|
946
|
+
y = Class.new(Sequel::Model)
|
947
|
+
y.columns :id, :x
|
948
|
+
a = z.load(:id => 1, :x => 3)
|
949
|
+
b = z.load(:id => 1, :x => 4)
|
950
|
+
c = z.load(:id => 2, :x => 3)
|
951
|
+
d = y.load(:id => 1, :x => 3)
|
952
|
+
|
953
|
+
a.should === b
|
954
|
+
a.should_not === c
|
955
|
+
a.should_not === d
|
956
|
+
end
|
957
|
+
|
958
|
+
specify "should always be false if the primary key is nil" do
|
959
|
+
z = Class.new(Sequel::Model)
|
960
|
+
z.columns :id, :x
|
961
|
+
y = Class.new(Sequel::Model)
|
962
|
+
y.columns :id, :x
|
963
|
+
a = z.new(:x => 3)
|
964
|
+
b = z.new(:x => 4)
|
965
|
+
c = z.new(:x => 3)
|
966
|
+
d = y.new(:x => 3)
|
967
|
+
|
968
|
+
a.should_not === b
|
969
|
+
a.should_not === c
|
970
|
+
a.should_not === d
|
971
|
+
end
|
972
|
+
end
|
973
|
+
|
974
|
+
describe Sequel::Model, "#hash" do
|
975
|
+
specify "should be the same only for objects with the same class and pk if the pk is not nil" do
|
976
|
+
z = Class.new(Sequel::Model)
|
977
|
+
z.columns :id, :x
|
978
|
+
y = Class.new(Sequel::Model)
|
979
|
+
y.columns :id, :x
|
980
|
+
a = z.load(:id => 1, :x => 3)
|
981
|
+
b = z.load(:id => 1, :x => 4)
|
982
|
+
c = z.load(:id => 2, :x => 3)
|
983
|
+
d = y.load(:id => 1, :x => 3)
|
984
|
+
|
985
|
+
a.hash.should == b.hash
|
986
|
+
a.hash.should_not == c.hash
|
987
|
+
a.hash.should_not == d.hash
|
988
|
+
end
|
989
|
+
|
990
|
+
specify "should be the same only for objects with the same class and values if the pk is nil" do
|
991
|
+
z = Class.new(Sequel::Model)
|
992
|
+
z.columns :id, :x
|
993
|
+
y = Class.new(Sequel::Model)
|
994
|
+
y.columns :id, :x
|
995
|
+
a = z.new(:x => 3)
|
996
|
+
b = z.new(:x => 4)
|
997
|
+
c = z.new(:x => 3)
|
998
|
+
d = y.new(:x => 3)
|
999
|
+
|
1000
|
+
a.hash.should_not == b.hash
|
1001
|
+
a.hash.should == c.hash
|
1002
|
+
a.hash.should_not == d.hash
|
1003
|
+
end
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
describe Sequel::Model, "#initialize" do
|
1007
|
+
before do
|
1008
|
+
@c = Class.new(Sequel::Model) do
|
1009
|
+
columns :id, :x
|
1010
|
+
end
|
1011
|
+
@c.strict_param_setting = false
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
specify "should accept values" do
|
1015
|
+
m = @c.new(:x => 2)
|
1016
|
+
m.values.should == {:x => 2}
|
1017
|
+
end
|
1018
|
+
|
1019
|
+
specify "should not modify the primary key" do
|
1020
|
+
m = @c.new(:id => 1, :x => 2)
|
1021
|
+
m.values.should == {:x => 2}
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
specify "should accept no values" do
|
1025
|
+
m = @c.new
|
1026
|
+
m.values.should == {}
|
1027
|
+
end
|
1028
|
+
|
1029
|
+
specify "should accept a block to execute" do
|
1030
|
+
m = @c.new {|o| o[:id] = 1234}
|
1031
|
+
m.id.should == 1234
|
1032
|
+
end
|
1033
|
+
|
1034
|
+
specify "should accept virtual attributes" do
|
1035
|
+
@c.send(:define_method, :blah=){|x| @blah = x}
|
1036
|
+
@c.send(:define_method, :blah){@blah}
|
1037
|
+
|
1038
|
+
m = @c.new(:x => 2, :blah => 3)
|
1039
|
+
m.values.should == {:x => 2}
|
1040
|
+
m.blah.should == 3
|
1041
|
+
end
|
1042
|
+
|
1043
|
+
specify "should convert string keys into symbol keys" do
|
1044
|
+
m = @c.new('x' => 2)
|
1045
|
+
m.values.should == {:x => 2}
|
1046
|
+
end
|
1047
|
+
end
|
1048
|
+
|
1049
|
+
describe Sequel::Model, ".create" do
|
1050
|
+
|
1051
|
+
before(:each) do
|
1052
|
+
MODEL_DB.reset
|
1053
|
+
@c = Class.new(Sequel::Model(:items)) do
|
1054
|
+
unrestrict_primary_key
|
1055
|
+
columns :x
|
1056
|
+
end
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
it "should be able to create rows in the associated table" do
|
1060
|
+
o = @c.create(:x => 1)
|
1061
|
+
o.class.should == @c
|
1062
|
+
MODEL_DB.sqls.should == ['INSERT INTO items (x) VALUES (1)', "SELECT * FROM items WHERE (id IN ('INSERT INTO items (x) VALUES (1)')) LIMIT 1"]
|
1063
|
+
end
|
1064
|
+
|
1065
|
+
it "should be able to create rows without any values specified" do
|
1066
|
+
o = @c.create
|
1067
|
+
o.class.should == @c
|
1068
|
+
MODEL_DB.sqls.should == ["INSERT INTO items DEFAULT VALUES", "SELECT * FROM items WHERE (id IN ('INSERT INTO items DEFAULT VALUES')) LIMIT 1"]
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
it "should accept a block and run it" do
|
1072
|
+
o1, o2, o3 = nil, nil, nil
|
1073
|
+
o = @c.create {|o4| o1 = o4; o3 = o4; o2 = :blah; o3.x = 333}
|
1074
|
+
o.class.should == @c
|
1075
|
+
o1.should === o
|
1076
|
+
o3.should === o
|
1077
|
+
o2.should == :blah
|
1078
|
+
MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (333)", "SELECT * FROM items WHERE (id IN ('INSERT INTO items (x) VALUES (333)')) LIMIT 1"]
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
it "should create a row for a model with custom primary key" do
|
1082
|
+
@c.set_primary_key :x
|
1083
|
+
o = @c.create(:x => 30)
|
1084
|
+
o.class.should == @c
|
1085
|
+
MODEL_DB.sqls.should == ["INSERT INTO items (x) VALUES (30)", "SELECT * FROM items WHERE (x = 30) LIMIT 1"]
|
1086
|
+
end
|
1087
|
+
end
|
1088
|
+
|
1089
|
+
describe Sequel::Model, "#refresh" do
|
1090
|
+
before do
|
1091
|
+
MODEL_DB.reset
|
1092
|
+
@c = Class.new(Sequel::Model(:items)) do
|
1093
|
+
unrestrict_primary_key
|
1094
|
+
columns :id, :x
|
1095
|
+
end
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
specify "should reload the instance values from the database" do
|
1099
|
+
@m = @c.new(:id => 555)
|
1100
|
+
@m[:x] = 'blah'
|
1101
|
+
@m.this.should_receive(:first).and_return({:x => 'kaboom', :id => 555})
|
1102
|
+
@m.refresh
|
1103
|
+
@m[:x].should == 'kaboom'
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
specify "should raise if the instance is not found" do
|
1107
|
+
@m = @c.new(:id => 555)
|
1108
|
+
@m.this.should_receive(:first).and_return(nil)
|
1109
|
+
proc {@m.refresh}.should raise_error(Sequel::Error)
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
specify "should be aliased by #reload" do
|
1113
|
+
@m = @c.new(:id => 555)
|
1114
|
+
@m.this.should_receive(:first).and_return({:x => 'kaboom', :id => 555})
|
1115
|
+
@m.reload
|
1116
|
+
@m[:x].should == 'kaboom'
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
specify "should remove cached associations" do
|
1120
|
+
@c.many_to_one :node, :class=>@c
|
1121
|
+
@m = @c.new(:id => 555)
|
1122
|
+
@m.associations[:node] = 15
|
1123
|
+
@m.reload
|
1124
|
+
@m.associations.should == {}
|
1125
|
+
end
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
describe Sequel::Model, "typecasting" do
|
1129
|
+
before do
|
1130
|
+
MODEL_DB.reset
|
1131
|
+
@c = Class.new(Sequel::Model(:items)) do
|
1132
|
+
columns :x
|
1133
|
+
end
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
after do
|
1137
|
+
Sequel.datetime_class = Time
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
specify "should not convert if typecasting is turned off" do
|
1141
|
+
@c.typecast_on_assignment = false
|
1142
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
|
1143
|
+
m = @c.new
|
1144
|
+
m.x = '1'
|
1145
|
+
m.x.should == '1'
|
1146
|
+
end
|
1147
|
+
|
1148
|
+
specify "should convert to integer for an integer field" do
|
1149
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
|
1150
|
+
m = @c.new
|
1151
|
+
m.x = '1'
|
1152
|
+
m.x.should == 1
|
1153
|
+
m.x = 1
|
1154
|
+
m.x.should == 1
|
1155
|
+
m.x = 1.3
|
1156
|
+
m.x.should == 1
|
1157
|
+
end
|
1158
|
+
|
1159
|
+
specify "should typecast '' to nil unless type is string or blob" do
|
1160
|
+
[:integer, :float, :decimal, :boolean, :date, :time, :datetime].each do |x|
|
1161
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>x}})
|
1162
|
+
m = @c.new
|
1163
|
+
m.x = ''
|
1164
|
+
m.x.should == nil
|
1165
|
+
end
|
1166
|
+
[:string, :blob].each do |x|
|
1167
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>x}})
|
1168
|
+
m = @c.new
|
1169
|
+
m.x = ''
|
1170
|
+
m.x.should == ''
|
1171
|
+
end
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
specify "should not typecast '' to nil if typecast_empty_string_to_nil is false" do
|
1175
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
|
1176
|
+
m = @c.new
|
1177
|
+
m.typecast_empty_string_to_nil = false
|
1178
|
+
proc{m.x = ''}.should raise_error
|
1179
|
+
@c.typecast_empty_string_to_nil = false
|
1180
|
+
proc{@c.new.x = ''}.should raise_error
|
1181
|
+
end
|
1182
|
+
|
1183
|
+
specify "should not typecast nil if NULLs are allowed" do
|
1184
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer,:allow_null=>true}})
|
1185
|
+
m = @c.new
|
1186
|
+
m.x = nil
|
1187
|
+
m.x.should == nil
|
1188
|
+
end
|
1189
|
+
|
1190
|
+
specify "should raise an error if attempting to typecast nil and NULLs are not allowed" do
|
1191
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer,:allow_null=>false}})
|
1192
|
+
proc{@c.new.x = nil}.should raise_error(Sequel::Error)
|
1193
|
+
proc{@c.new.x = ''}.should raise_error(Sequel::Error)
|
1194
|
+
end
|
1195
|
+
|
1196
|
+
specify "should not raise an error if NULLs are not allowed and typecasting is turned off" do
|
1197
|
+
@c.typecast_on_assignment = false
|
1198
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer,:allow_null=>false}})
|
1199
|
+
m = @c.new
|
1200
|
+
m.x = nil
|
1201
|
+
m.x.should == nil
|
1202
|
+
end
|
1203
|
+
|
1204
|
+
specify "should not raise when typecasting nil to NOT NULL column but raise_on_typecast_failure is off" do
|
1205
|
+
@c.raise_on_typecast_failure = false
|
1206
|
+
@c.typecast_on_assignment = true
|
1207
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer,:allow_null=>false}})
|
1208
|
+
m = @c.new
|
1209
|
+
m.x = ''
|
1210
|
+
m.x.should == nil
|
1211
|
+
m.x = nil
|
1212
|
+
m.x.should == nil
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
specify "should raise an error if invalid data is used in an integer field" do
|
1216
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
|
1217
|
+
proc{@c.new.x = 'a'}.should raise_error(Sequel::InvalidValue)
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
specify "should assign value if raise_on_typecast_failure is off and assigning invalid integer" do
|
1221
|
+
@c.raise_on_typecast_failure = false
|
1222
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:integer}})
|
1223
|
+
model = @c.new
|
1224
|
+
model.x = '1d'
|
1225
|
+
model.x.should == '1d'
|
1226
|
+
end
|
1227
|
+
|
1228
|
+
specify "should convert to float for a float field" do
|
1229
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:float}})
|
1230
|
+
m = @c.new
|
1231
|
+
m.x = '1.3'
|
1232
|
+
m.x.should == 1.3
|
1233
|
+
m.x = 1
|
1234
|
+
m.x.should == 1.0
|
1235
|
+
m.x = 1.3
|
1236
|
+
m.x.should == 1.3
|
1237
|
+
end
|
1238
|
+
|
1239
|
+
specify "should raise an error if invalid data is used in an float field" do
|
1240
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:float}})
|
1241
|
+
proc{@c.new.x = 'a'}.should raise_error(Sequel::InvalidValue)
|
1242
|
+
end
|
1243
|
+
|
1244
|
+
specify "should assign value if raise_on_typecast_failure is off and assigning invalid float" do
|
1245
|
+
@c.raise_on_typecast_failure = false
|
1246
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:float}})
|
1247
|
+
model = @c.new
|
1248
|
+
model.x = '1d'
|
1249
|
+
model.x.should == '1d'
|
1250
|
+
end
|
1251
|
+
|
1252
|
+
specify "should convert to BigDecimal for a decimal field" do
|
1253
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:decimal}})
|
1254
|
+
m = @c.new
|
1255
|
+
bd = BigDecimal.new('1.0')
|
1256
|
+
m.x = '1.0'
|
1257
|
+
m.x.should == bd
|
1258
|
+
m.x = 1.0
|
1259
|
+
m.x.should == bd
|
1260
|
+
m.x = 1
|
1261
|
+
m.x.should == bd
|
1262
|
+
m.x = bd
|
1263
|
+
m.x.should == bd
|
1264
|
+
end
|
1265
|
+
|
1266
|
+
specify "should raise an error if invalid data is used in an decimal field" do
|
1267
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:decimal}})
|
1268
|
+
proc{@c.new.x = Date.today}.should raise_error(Sequel::InvalidValue)
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
specify "should assign value if raise_on_typecast_failure is off and assigning invalid decimal" do
|
1272
|
+
@c.raise_on_typecast_failure = false
|
1273
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:decimal}})
|
1274
|
+
model = @c.new
|
1275
|
+
time = Time.now
|
1276
|
+
model.x = time
|
1277
|
+
model.x.should == time
|
1278
|
+
end
|
1279
|
+
|
1280
|
+
specify "should convert to string for a string field" do
|
1281
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:string}})
|
1282
|
+
m = @c.new
|
1283
|
+
m.x = '1.3'
|
1284
|
+
m.x.should == '1.3'
|
1285
|
+
m.x = 1
|
1286
|
+
m.x.should == '1'
|
1287
|
+
m.x = 1.3
|
1288
|
+
m.x.should == '1.3'
|
1289
|
+
end
|
1290
|
+
|
1291
|
+
specify "should convert to boolean for a boolean field" do
|
1292
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:boolean}})
|
1293
|
+
m = @c.new
|
1294
|
+
m.x = '1.3'
|
1295
|
+
m.x.should == true
|
1296
|
+
m.x = 1
|
1297
|
+
m.x.should == true
|
1298
|
+
m.x = 1.3
|
1299
|
+
m.x.should == true
|
1300
|
+
m.x = 't'
|
1301
|
+
m.x.should == true
|
1302
|
+
m.x = 'T'
|
1303
|
+
m.x.should == true
|
1304
|
+
m.x = true
|
1305
|
+
m.x.should == true
|
1306
|
+
m.x = nil
|
1307
|
+
m.x.should == nil
|
1308
|
+
m.x = ''
|
1309
|
+
m.x.should == nil
|
1310
|
+
m.x = []
|
1311
|
+
m.x.should == nil
|
1312
|
+
m.x = 'f'
|
1313
|
+
m.x.should == false
|
1314
|
+
m.x = 'F'
|
1315
|
+
m.x.should == false
|
1316
|
+
m.x = 'false'
|
1317
|
+
m.x.should == false
|
1318
|
+
m.x = 'FALSE'
|
1319
|
+
m.x.should == false
|
1320
|
+
m.x = '0'
|
1321
|
+
m.x.should == false
|
1322
|
+
m.x = 0
|
1323
|
+
m.x.should == false
|
1324
|
+
m.x = false
|
1325
|
+
m.x.should == false
|
1326
|
+
end
|
1327
|
+
|
1328
|
+
specify "should convert to date for a date field" do
|
1329
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:date}})
|
1330
|
+
m = @c.new
|
1331
|
+
y = Date.new(2007,10,21)
|
1332
|
+
m.x = '2007-10-21'
|
1333
|
+
m.x.should == y
|
1334
|
+
m.x = Date.parse('2007-10-21')
|
1335
|
+
m.x.should == y
|
1336
|
+
m.x = Time.parse('2007-10-21')
|
1337
|
+
m.x.should == y
|
1338
|
+
m.x = DateTime.parse('2007-10-21')
|
1339
|
+
m.x.should == y
|
1340
|
+
end
|
1341
|
+
|
1342
|
+
specify "should accept a hash with symbol or string keys for a date field" do
|
1343
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:date}})
|
1344
|
+
m = @c.new
|
1345
|
+
y = Date.new(2007,10,21)
|
1346
|
+
m.x = {:year=>2007, :month=>10, :day=>21}
|
1347
|
+
m.x.should == y
|
1348
|
+
m.x = {'year'=>'2007', 'month'=>'10', 'day'=>'21'}
|
1349
|
+
m.x.should == y
|
1350
|
+
end
|
1351
|
+
|
1352
|
+
specify "should raise an error if invalid data is used in a date field" do
|
1353
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:date}})
|
1354
|
+
proc{@c.new.x = 'a'}.should raise_error(Sequel::InvalidValue)
|
1355
|
+
proc{@c.new.x = 100}.should raise_error(Sequel::InvalidValue)
|
1356
|
+
end
|
1357
|
+
|
1358
|
+
specify "should assign value if raise_on_typecast_failure is off and assigning invalid date" do
|
1359
|
+
@c.raise_on_typecast_failure = false
|
1360
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:date}})
|
1361
|
+
model = @c.new
|
1362
|
+
model.x = 4
|
1363
|
+
model.x.should == 4
|
1364
|
+
end
|
1365
|
+
|
1366
|
+
specify "should convert to time for a time field" do
|
1367
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:time}})
|
1368
|
+
m = @c.new
|
1369
|
+
x = '10:20:30'
|
1370
|
+
y = Time.parse(x)
|
1371
|
+
m.x = x
|
1372
|
+
m.x.should == y
|
1373
|
+
m.x = y
|
1374
|
+
m.x.should == y
|
1375
|
+
end
|
1376
|
+
|
1377
|
+
specify "should accept a hash with symbol or string keys for a time field" do
|
1378
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:time}})
|
1379
|
+
m = @c.new
|
1380
|
+
y = Time.parse('10:20:30')
|
1381
|
+
m.x = {:hour=>10, :minute=>20, :second=>30}
|
1382
|
+
m.x.should == y
|
1383
|
+
m.x = {'hour'=>'10', 'minute'=>'20', 'second'=>'30'}
|
1384
|
+
m.x.should == y
|
1385
|
+
end
|
1386
|
+
|
1387
|
+
specify "should raise an error if invalid data is used in a time field" do
|
1388
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:time}})
|
1389
|
+
proc{@c.new.x = '0000'}.should raise_error
|
1390
|
+
proc{@c.new.x = 'a'}.should_not raise_error # Valid Time
|
1391
|
+
proc{@c.new.x = Date.parse('2008-10-21')}.should raise_error(Sequel::InvalidValue)
|
1392
|
+
proc{@c.new.x = DateTime.parse('2008-10-21')}.should raise_error(Sequel::InvalidValue)
|
1393
|
+
end
|
1394
|
+
|
1395
|
+
specify "should assign value if raise_on_typecast_failure is off and assigning invalid time" do
|
1396
|
+
@c.raise_on_typecast_failure = false
|
1397
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:time}})
|
1398
|
+
model = @c.new
|
1399
|
+
model.x = '0000'
|
1400
|
+
model.x.should == '0000'
|
1401
|
+
end
|
1402
|
+
|
1403
|
+
specify "should convert to the Sequel.datetime_class for a datetime field" do
|
1404
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:datetime}})
|
1405
|
+
m = @c.new
|
1406
|
+
x = '2007-10-21T10:20:30-07:00'
|
1407
|
+
y = Time.parse(x)
|
1408
|
+
m.x = x
|
1409
|
+
m.x.should == y
|
1410
|
+
m.x = DateTime.parse(x)
|
1411
|
+
m.x.should == y
|
1412
|
+
m.x = Time.parse(x)
|
1413
|
+
m.x.should == y
|
1414
|
+
m.x = Date.parse('2007-10-21')
|
1415
|
+
m.x.should == Time.parse('2007-10-21')
|
1416
|
+
Sequel.datetime_class = DateTime
|
1417
|
+
y = DateTime.parse(x)
|
1418
|
+
m.x = x
|
1419
|
+
m.x.should == y
|
1420
|
+
m.x = DateTime.parse(x)
|
1421
|
+
m.x.should == y
|
1422
|
+
m.x = Time.parse(x)
|
1423
|
+
m.x.should == y
|
1424
|
+
m.x = Date.parse('2007-10-21')
|
1425
|
+
m.x.should == DateTime.parse('2007-10-21')
|
1426
|
+
end
|
1427
|
+
|
1428
|
+
specify "should accept a hash with symbol or string keys for a datetime field" do
|
1429
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:datetime}})
|
1430
|
+
m = @c.new
|
1431
|
+
y = Time.parse('2007-10-21 10:20:30')
|
1432
|
+
m.x = {:year=>2007, :month=>10, :day=>21, :hour=>10, :minute=>20, :second=>30}
|
1433
|
+
m.x.should == y
|
1434
|
+
m.x = {'year'=>'2007', 'month'=>'10', 'day'=>'21', 'hour'=>'10', 'minute'=>'20', 'second'=>'30'}
|
1435
|
+
m.x.should == y
|
1436
|
+
Sequel.datetime_class = DateTime
|
1437
|
+
y = DateTime.parse('2007-10-21 10:20:30')
|
1438
|
+
m.x = {:year=>2007, :month=>10, :day=>21, :hour=>10, :minute=>20, :second=>30}
|
1439
|
+
m.x.should == y
|
1440
|
+
m.x = {'year'=>'2007', 'month'=>'10', 'day'=>'21', 'hour'=>'10', 'minute'=>'20', 'second'=>'30'}
|
1441
|
+
m.x.should == y
|
1442
|
+
end
|
1443
|
+
|
1444
|
+
specify "should raise an error if invalid data is used in a datetime field" do
|
1445
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:datetime}})
|
1446
|
+
proc{@c.new.x = '0000'}.should raise_error(Sequel::InvalidValue)
|
1447
|
+
proc{@c.new.x = 'a'}.should_not raise_error # Valid Time
|
1448
|
+
Sequel.datetime_class = DateTime
|
1449
|
+
proc{@c.new.x = '0000'}.should raise_error(Sequel::InvalidValue)
|
1450
|
+
proc{@c.new.x = 'a'}.should raise_error(Sequel::InvalidValue)
|
1451
|
+
end
|
1452
|
+
|
1453
|
+
specify "should assign value if raise_on_typecast_failure is off and assigning invalid datetime" do
|
1454
|
+
@c.raise_on_typecast_failure = false
|
1455
|
+
@c.instance_variable_set(:@db_schema, {:x=>{:type=>:datetime}})
|
1456
|
+
model = @c.new
|
1457
|
+
model.x = '0000'
|
1458
|
+
model.x.should == '0000'
|
1459
|
+
Sequel.datetime_class = DateTime
|
1460
|
+
model = @c.new
|
1461
|
+
model.x = '0000'
|
1462
|
+
model.x.should == '0000'
|
1463
|
+
model.x = 'a'
|
1464
|
+
model.x.should == 'a'
|
1465
|
+
end
|
1466
|
+
end
|
1467
|
+
|
1468
|
+
describe "Model#lock!" do
|
1469
|
+
before do
|
1470
|
+
@c = Class.new(Sequel::Model(:items)) do
|
1471
|
+
columns :id
|
1472
|
+
end
|
1473
|
+
ds = @c.dataset
|
1474
|
+
def ds.fetch_rows(sql)
|
1475
|
+
db.execute(sql)
|
1476
|
+
yield({:id=>1})
|
1477
|
+
end
|
1478
|
+
MODEL_DB.reset
|
1479
|
+
end
|
1480
|
+
|
1481
|
+
it "should do nothing if the record is a new record" do
|
1482
|
+
o = @c.new
|
1483
|
+
called = false
|
1484
|
+
o.meta_def(:_refresh){|x| called = true; super(x)}
|
1485
|
+
x = o.lock!
|
1486
|
+
x.should == o
|
1487
|
+
called.should == false
|
1488
|
+
MODEL_DB.sqls.should == []
|
1489
|
+
end
|
1490
|
+
|
1491
|
+
it "should refresh the record using for_update if it is not a new record" do
|
1492
|
+
o = @c.load(:id => 1)
|
1493
|
+
called = false
|
1494
|
+
o.meta_def(:_refresh){|x| called = true; super(x)}
|
1495
|
+
x = o.lock!
|
1496
|
+
x.should == o
|
1497
|
+
called.should == true
|
1498
|
+
MODEL_DB.sqls.should == ["SELECT * FROM items WHERE (id = 1) LIMIT 1 FOR UPDATE"]
|
1499
|
+
end
|
1500
|
+
end
|