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.
Files changed (237) hide show
  1. data/CHANGELOG +3134 -0
  2. data/COPYING +19 -0
  3. data/README.rdoc +723 -0
  4. data/Rakefile +193 -0
  5. data/bin/sequel +196 -0
  6. data/doc/advanced_associations.rdoc +644 -0
  7. data/doc/cheat_sheet.rdoc +218 -0
  8. data/doc/dataset_basics.rdoc +106 -0
  9. data/doc/dataset_filtering.rdoc +158 -0
  10. data/doc/opening_databases.rdoc +296 -0
  11. data/doc/prepared_statements.rdoc +104 -0
  12. data/doc/reflection.rdoc +84 -0
  13. data/doc/release_notes/1.0.txt +38 -0
  14. data/doc/release_notes/1.1.txt +143 -0
  15. data/doc/release_notes/1.3.txt +101 -0
  16. data/doc/release_notes/1.4.0.txt +53 -0
  17. data/doc/release_notes/1.5.0.txt +155 -0
  18. data/doc/release_notes/2.0.0.txt +298 -0
  19. data/doc/release_notes/2.1.0.txt +271 -0
  20. data/doc/release_notes/2.10.0.txt +328 -0
  21. data/doc/release_notes/2.11.0.txt +215 -0
  22. data/doc/release_notes/2.12.0.txt +534 -0
  23. data/doc/release_notes/2.2.0.txt +253 -0
  24. data/doc/release_notes/2.3.0.txt +88 -0
  25. data/doc/release_notes/2.4.0.txt +106 -0
  26. data/doc/release_notes/2.5.0.txt +137 -0
  27. data/doc/release_notes/2.6.0.txt +157 -0
  28. data/doc/release_notes/2.7.0.txt +166 -0
  29. data/doc/release_notes/2.8.0.txt +171 -0
  30. data/doc/release_notes/2.9.0.txt +97 -0
  31. data/doc/release_notes/3.0.0.txt +221 -0
  32. data/doc/release_notes/3.1.0.txt +406 -0
  33. data/doc/release_notes/3.10.0.txt +286 -0
  34. data/doc/release_notes/3.2.0.txt +268 -0
  35. data/doc/release_notes/3.3.0.txt +192 -0
  36. data/doc/release_notes/3.4.0.txt +325 -0
  37. data/doc/release_notes/3.5.0.txt +510 -0
  38. data/doc/release_notes/3.6.0.txt +366 -0
  39. data/doc/release_notes/3.7.0.txt +179 -0
  40. data/doc/release_notes/3.8.0.txt +151 -0
  41. data/doc/release_notes/3.9.0.txt +233 -0
  42. data/doc/schema.rdoc +36 -0
  43. data/doc/sharding.rdoc +113 -0
  44. data/doc/virtual_rows.rdoc +205 -0
  45. data/lib/sequel.rb +1 -0
  46. data/lib/sequel/adapters/ado.rb +90 -0
  47. data/lib/sequel/adapters/ado/mssql.rb +30 -0
  48. data/lib/sequel/adapters/amalgalite.rb +176 -0
  49. data/lib/sequel/adapters/db2.rb +139 -0
  50. data/lib/sequel/adapters/dbi.rb +113 -0
  51. data/lib/sequel/adapters/do.rb +188 -0
  52. data/lib/sequel/adapters/do/mysql.rb +49 -0
  53. data/lib/sequel/adapters/do/postgres.rb +91 -0
  54. data/lib/sequel/adapters/do/sqlite.rb +40 -0
  55. data/lib/sequel/adapters/firebird.rb +283 -0
  56. data/lib/sequel/adapters/informix.rb +77 -0
  57. data/lib/sequel/adapters/jdbc.rb +587 -0
  58. data/lib/sequel/adapters/jdbc/as400.rb +58 -0
  59. data/lib/sequel/adapters/jdbc/h2.rb +133 -0
  60. data/lib/sequel/adapters/jdbc/mssql.rb +57 -0
  61. data/lib/sequel/adapters/jdbc/mysql.rb +78 -0
  62. data/lib/sequel/adapters/jdbc/oracle.rb +50 -0
  63. data/lib/sequel/adapters/jdbc/postgresql.rb +108 -0
  64. data/lib/sequel/adapters/jdbc/sqlite.rb +55 -0
  65. data/lib/sequel/adapters/mysql.rb +421 -0
  66. data/lib/sequel/adapters/odbc.rb +143 -0
  67. data/lib/sequel/adapters/odbc/mssql.rb +42 -0
  68. data/lib/sequel/adapters/openbase.rb +64 -0
  69. data/lib/sequel/adapters/oracle.rb +131 -0
  70. data/lib/sequel/adapters/postgres.rb +504 -0
  71. data/lib/sequel/adapters/shared/mssql.rb +490 -0
  72. data/lib/sequel/adapters/shared/mysql.rb +498 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +195 -0
  74. data/lib/sequel/adapters/shared/postgres.rb +830 -0
  75. data/lib/sequel/adapters/shared/progress.rb +44 -0
  76. data/lib/sequel/adapters/shared/sqlite.rb +389 -0
  77. data/lib/sequel/adapters/sqlite.rb +224 -0
  78. data/lib/sequel/adapters/utils/stored_procedures.rb +84 -0
  79. data/lib/sequel/connection_pool.rb +99 -0
  80. data/lib/sequel/connection_pool/sharded_single.rb +84 -0
  81. data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
  82. data/lib/sequel/connection_pool/single.rb +29 -0
  83. data/lib/sequel/connection_pool/threaded.rb +150 -0
  84. data/lib/sequel/core.rb +293 -0
  85. data/lib/sequel/core_sql.rb +241 -0
  86. data/lib/sequel/database.rb +1079 -0
  87. data/lib/sequel/database/schema_generator.rb +327 -0
  88. data/lib/sequel/database/schema_methods.rb +203 -0
  89. data/lib/sequel/database/schema_sql.rb +320 -0
  90. data/lib/sequel/dataset.rb +32 -0
  91. data/lib/sequel/dataset/actions.rb +441 -0
  92. data/lib/sequel/dataset/features.rb +86 -0
  93. data/lib/sequel/dataset/graph.rb +254 -0
  94. data/lib/sequel/dataset/misc.rb +119 -0
  95. data/lib/sequel/dataset/mutation.rb +64 -0
  96. data/lib/sequel/dataset/prepared_statements.rb +227 -0
  97. data/lib/sequel/dataset/query.rb +709 -0
  98. data/lib/sequel/dataset/sql.rb +996 -0
  99. data/lib/sequel/exceptions.rb +51 -0
  100. data/lib/sequel/extensions/blank.rb +43 -0
  101. data/lib/sequel/extensions/inflector.rb +242 -0
  102. data/lib/sequel/extensions/looser_typecasting.rb +21 -0
  103. data/lib/sequel/extensions/migration.rb +239 -0
  104. data/lib/sequel/extensions/named_timezones.rb +61 -0
  105. data/lib/sequel/extensions/pagination.rb +100 -0
  106. data/lib/sequel/extensions/pretty_table.rb +82 -0
  107. data/lib/sequel/extensions/query.rb +52 -0
  108. data/lib/sequel/extensions/schema_dumper.rb +271 -0
  109. data/lib/sequel/extensions/sql_expr.rb +122 -0
  110. data/lib/sequel/extensions/string_date_time.rb +46 -0
  111. data/lib/sequel/extensions/thread_local_timezones.rb +48 -0
  112. data/lib/sequel/metaprogramming.rb +9 -0
  113. data/lib/sequel/model.rb +120 -0
  114. data/lib/sequel/model/associations.rb +1514 -0
  115. data/lib/sequel/model/base.rb +1069 -0
  116. data/lib/sequel/model/default_inflections.rb +45 -0
  117. data/lib/sequel/model/errors.rb +39 -0
  118. data/lib/sequel/model/exceptions.rb +21 -0
  119. data/lib/sequel/model/inflections.rb +162 -0
  120. data/lib/sequel/model/plugins.rb +70 -0
  121. data/lib/sequel/plugins/active_model.rb +59 -0
  122. data/lib/sequel/plugins/association_dependencies.rb +103 -0
  123. data/lib/sequel/plugins/association_proxies.rb +41 -0
  124. data/lib/sequel/plugins/boolean_readers.rb +53 -0
  125. data/lib/sequel/plugins/caching.rb +141 -0
  126. data/lib/sequel/plugins/class_table_inheritance.rb +214 -0
  127. data/lib/sequel/plugins/composition.rb +138 -0
  128. data/lib/sequel/plugins/force_encoding.rb +72 -0
  129. data/lib/sequel/plugins/hook_class_methods.rb +126 -0
  130. data/lib/sequel/plugins/identity_map.rb +116 -0
  131. data/lib/sequel/plugins/instance_filters.rb +98 -0
  132. data/lib/sequel/plugins/instance_hooks.rb +57 -0
  133. data/lib/sequel/plugins/lazy_attributes.rb +77 -0
  134. data/lib/sequel/plugins/many_through_many.rb +208 -0
  135. data/lib/sequel/plugins/nested_attributes.rb +206 -0
  136. data/lib/sequel/plugins/optimistic_locking.rb +81 -0
  137. data/lib/sequel/plugins/rcte_tree.rb +281 -0
  138. data/lib/sequel/plugins/schema.rb +66 -0
  139. data/lib/sequel/plugins/serialization.rb +166 -0
  140. data/lib/sequel/plugins/single_table_inheritance.rb +74 -0
  141. data/lib/sequel/plugins/subclasses.rb +45 -0
  142. data/lib/sequel/plugins/tactical_eager_loading.rb +61 -0
  143. data/lib/sequel/plugins/timestamps.rb +87 -0
  144. data/lib/sequel/plugins/touch.rb +118 -0
  145. data/lib/sequel/plugins/typecast_on_load.rb +72 -0
  146. data/lib/sequel/plugins/validation_class_methods.rb +405 -0
  147. data/lib/sequel/plugins/validation_helpers.rb +223 -0
  148. data/lib/sequel/sql.rb +1020 -0
  149. data/lib/sequel/timezones.rb +161 -0
  150. data/lib/sequel/version.rb +12 -0
  151. data/lib/sequel_core.rb +1 -0
  152. data/lib/sequel_model.rb +1 -0
  153. data/spec/adapters/firebird_spec.rb +407 -0
  154. data/spec/adapters/informix_spec.rb +97 -0
  155. data/spec/adapters/mssql_spec.rb +403 -0
  156. data/spec/adapters/mysql_spec.rb +1019 -0
  157. data/spec/adapters/oracle_spec.rb +286 -0
  158. data/spec/adapters/postgres_spec.rb +969 -0
  159. data/spec/adapters/spec_helper.rb +51 -0
  160. data/spec/adapters/sqlite_spec.rb +432 -0
  161. data/spec/core/connection_pool_spec.rb +808 -0
  162. data/spec/core/core_sql_spec.rb +417 -0
  163. data/spec/core/database_spec.rb +1662 -0
  164. data/spec/core/dataset_spec.rb +3827 -0
  165. data/spec/core/expression_filters_spec.rb +595 -0
  166. data/spec/core/object_graph_spec.rb +296 -0
  167. data/spec/core/schema_generator_spec.rb +159 -0
  168. data/spec/core/schema_spec.rb +830 -0
  169. data/spec/core/spec_helper.rb +56 -0
  170. data/spec/core/version_spec.rb +7 -0
  171. data/spec/extensions/active_model_spec.rb +76 -0
  172. data/spec/extensions/association_dependencies_spec.rb +127 -0
  173. data/spec/extensions/association_proxies_spec.rb +50 -0
  174. data/spec/extensions/blank_spec.rb +67 -0
  175. data/spec/extensions/boolean_readers_spec.rb +92 -0
  176. data/spec/extensions/caching_spec.rb +250 -0
  177. data/spec/extensions/class_table_inheritance_spec.rb +252 -0
  178. data/spec/extensions/composition_spec.rb +194 -0
  179. data/spec/extensions/force_encoding_spec.rb +117 -0
  180. data/spec/extensions/hook_class_methods_spec.rb +470 -0
  181. data/spec/extensions/identity_map_spec.rb +202 -0
  182. data/spec/extensions/inflector_spec.rb +181 -0
  183. data/spec/extensions/instance_filters_spec.rb +55 -0
  184. data/spec/extensions/instance_hooks_spec.rb +133 -0
  185. data/spec/extensions/lazy_attributes_spec.rb +153 -0
  186. data/spec/extensions/looser_typecasting_spec.rb +39 -0
  187. data/spec/extensions/many_through_many_spec.rb +884 -0
  188. data/spec/extensions/migration_spec.rb +332 -0
  189. data/spec/extensions/named_timezones_spec.rb +72 -0
  190. data/spec/extensions/nested_attributes_spec.rb +396 -0
  191. data/spec/extensions/optimistic_locking_spec.rb +100 -0
  192. data/spec/extensions/pagination_spec.rb +99 -0
  193. data/spec/extensions/pretty_table_spec.rb +91 -0
  194. data/spec/extensions/query_spec.rb +85 -0
  195. data/spec/extensions/rcte_tree_spec.rb +205 -0
  196. data/spec/extensions/schema_dumper_spec.rb +357 -0
  197. data/spec/extensions/schema_spec.rb +127 -0
  198. data/spec/extensions/serialization_spec.rb +209 -0
  199. data/spec/extensions/single_table_inheritance_spec.rb +96 -0
  200. data/spec/extensions/spec_helper.rb +91 -0
  201. data/spec/extensions/sql_expr_spec.rb +89 -0
  202. data/spec/extensions/string_date_time_spec.rb +93 -0
  203. data/spec/extensions/subclasses_spec.rb +52 -0
  204. data/spec/extensions/tactical_eager_loading_spec.rb +65 -0
  205. data/spec/extensions/thread_local_timezones_spec.rb +45 -0
  206. data/spec/extensions/timestamps_spec.rb +150 -0
  207. data/spec/extensions/touch_spec.rb +155 -0
  208. data/spec/extensions/typecast_on_load_spec.rb +69 -0
  209. data/spec/extensions/validation_class_methods_spec.rb +984 -0
  210. data/spec/extensions/validation_helpers_spec.rb +438 -0
  211. data/spec/integration/associations_test.rb +281 -0
  212. data/spec/integration/database_test.rb +26 -0
  213. data/spec/integration/dataset_test.rb +963 -0
  214. data/spec/integration/eager_loader_test.rb +734 -0
  215. data/spec/integration/model_test.rb +130 -0
  216. data/spec/integration/plugin_test.rb +814 -0
  217. data/spec/integration/prepared_statement_test.rb +213 -0
  218. data/spec/integration/schema_test.rb +361 -0
  219. data/spec/integration/spec_helper.rb +73 -0
  220. data/spec/integration/timezone_test.rb +55 -0
  221. data/spec/integration/transaction_test.rb +122 -0
  222. data/spec/integration/type_test.rb +96 -0
  223. data/spec/model/association_reflection_spec.rb +175 -0
  224. data/spec/model/associations_spec.rb +2633 -0
  225. data/spec/model/base_spec.rb +418 -0
  226. data/spec/model/dataset_methods_spec.rb +78 -0
  227. data/spec/model/eager_loading_spec.rb +1391 -0
  228. data/spec/model/hooks_spec.rb +240 -0
  229. data/spec/model/inflector_spec.rb +26 -0
  230. data/spec/model/model_spec.rb +593 -0
  231. data/spec/model/plugins_spec.rb +236 -0
  232. data/spec/model/record_spec.rb +1500 -0
  233. data/spec/model/spec_helper.rb +97 -0
  234. data/spec/model/validations_spec.rb +153 -0
  235. data/spec/rcov.opts +6 -0
  236. data/spec/spec_config.rb.example +10 -0
  237. metadata +346 -0
@@ -0,0 +1,194 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ require 'yaml'
4
+ require 'json'
5
+
6
+ describe "Serialization plugin" do
7
+ before do
8
+ @c = Class.new(Sequel::Model(:items))
9
+ @c.plugin :composition
10
+ @c.columns :id, :year, :month, :day
11
+ @o = @c.load(:id=>1, :year=>1, :month=>2, :day=>3)
12
+ MODEL_DB.reset
13
+ end
14
+
15
+ it ".composition should add compositions" do
16
+ @o.should_not respond_to(:date)
17
+ @c.composition :date, :mapping=>[:year, :month, :day]
18
+ @o.date.should == Date.new(1, 2, 3)
19
+ end
20
+
21
+ it "loading the plugin twice should not remove existing compositions" do
22
+ @c.composition :date, :mapping=>[:year, :month, :day]
23
+ @c.plugin :composition
24
+ @c.compositions.keys.should == [:date]
25
+ end
26
+
27
+ it ".composition should raise an error if :composer and :decomposer options are not present and :mapping option is not provided" do
28
+ proc{@c.composition :date}.should raise_error(Sequel::Error)
29
+ proc{@c.composition :date, :composer=>proc{}, :decomposer=>proc{}}.should_not raise_error
30
+ proc{@c.composition :date, :mapping=>[]}.should_not raise_error
31
+ end
32
+
33
+ it ".compositions should return the reflection hash of compositions" do
34
+ @c.compositions.should == {}
35
+ @c.composition :date, :mapping=>[:year, :month, :day]
36
+ @c.compositions.keys.should == [:date]
37
+ r = @c.compositions.values.first
38
+ r[:mapping].should == [:year, :month, :day]
39
+ r[:composer].should be_a_kind_of(Proc)
40
+ r[:decomposer].should be_a_kind_of(Proc)
41
+ end
42
+
43
+ it "#compositions should be a hash of cached values of compositions" do
44
+ @o.compositions.should == {}
45
+ @c.composition :date, :mapping=>[:year, :month, :day]
46
+ @o.date
47
+ @o.compositions.should == {:date=>Date.new(1, 2, 3)}
48
+ end
49
+
50
+ it "should work with custom :composer and :decomposer options" do
51
+ @c.composition :date, :composer=>proc{Date.new(year+1, month+2, day+3)}, :decomposer=>proc{[:year, :month, :day].each{|s| self.send("#{s}=", date.send(s) * 2)}}
52
+ @o.date.should == Date.new(2, 4, 6)
53
+ @o.save
54
+ MODEL_DB.sqls.last.should include("year = 4")
55
+ MODEL_DB.sqls.last.should include("month = 8")
56
+ MODEL_DB.sqls.last.should include("day = 12")
57
+ end
58
+
59
+ it "should allow call super in composition getter and setter method definition in class" do
60
+ @c.composition :date, :mapping=>[:year, :month, :day]
61
+ @c.class_eval do
62
+ def date
63
+ super + 1
64
+ end
65
+ def date=(v)
66
+ super(v - 3)
67
+ end
68
+ end
69
+ @o.date.should == Date.new(1, 2, 4)
70
+ @o.compositions[:date].should == Date.new(1, 2, 3)
71
+ @o.date = Date.new(1, 3, 5)
72
+ @o.compositions[:date].should == Date.new(1, 3, 2)
73
+ @o.date.should == Date.new(1, 3, 3)
74
+ end
75
+
76
+ it "should mark the object as modified whenever the composition is set" do
77
+ @c.composition :date, :mapping=>[:year, :month, :day]
78
+ @o.modified?.should == false
79
+ @o.date = Date.new(3, 4, 5)
80
+ @o.modified?.should == true
81
+ end
82
+
83
+ it "should only decompose existing compositions" do
84
+ called = false
85
+ @c.composition :date, :composer=>proc{}, :decomposer=>proc{called = true}
86
+ called.should == false
87
+ @o.save
88
+ called.should == false
89
+ @o.date = Date.new(1,2,3)
90
+ called.should == false
91
+ @o.save_changes
92
+ called.should == true
93
+ end
94
+
95
+ it "should clear compositions cache when reloading" do
96
+ @c.composition :date, :composer=>proc{}, :decomposer=>proc{called = true}
97
+ @o.date = Date.new(3, 4, 5)
98
+ @o.reload
99
+ @o.compositions.should == {}
100
+ end
101
+
102
+ it "should instantiate compositions lazily" do
103
+ @c.composition :date, :mapping=>[:year, :month, :day]
104
+ @o.compositions.should == {}
105
+ @o.date
106
+ @o.compositions.should == {:date=>Date.new(1,2,3)}
107
+ end
108
+
109
+ it "should cache value of composition" do
110
+ times = 0
111
+ @c.composition :date, :composer=>proc{times+=1}, :decomposer=>proc{called = true}
112
+ times.should == 0
113
+ @o.date
114
+ times.should == 1
115
+ @o.date
116
+ times.should == 1
117
+ end
118
+
119
+ it ":class option should take an string, symbol, or class" do
120
+ @c.composition :date1, :class=>'Date', :mapping=>[:year, :month, :day]
121
+ @c.composition :date2, :class=>:Date, :mapping=>[:year, :month, :day]
122
+ @c.composition :date3, :class=>Date, :mapping=>[:year, :month, :day]
123
+ @o.date1.should == Date.new(1, 2, 3)
124
+ @o.date2.should == Date.new(1, 2, 3)
125
+ @o.date3.should == Date.new(1, 2, 3)
126
+ end
127
+
128
+ it ":mapping option should work with a single array of symbols" do
129
+ c = Class.new do
130
+ def initialize(y, m)
131
+ @y, @m = y, m
132
+ end
133
+ def year
134
+ @y * 2
135
+ end
136
+ def month
137
+ @m * 3
138
+ end
139
+ end
140
+ @c.composition :date, :class=>c, :mapping=>[:year, :month]
141
+ @o.date.year.should == 2
142
+ @o.date.month.should == 6
143
+ @o.date = c.new(3, 4)
144
+ @o.save
145
+ MODEL_DB.sqls.last.should include("year = 6")
146
+ MODEL_DB.sqls.last.should include("month = 12")
147
+ end
148
+
149
+ it ":mapping option should work with an array of two pairs of symbols" do
150
+ c = Class.new do
151
+ def initialize(y, m)
152
+ @y, @m = y, m
153
+ end
154
+ def y
155
+ @y * 2
156
+ end
157
+ def m
158
+ @m * 3
159
+ end
160
+ end
161
+ @c.composition :date, :class=>c, :mapping=>[[:year, :y], [:month, :m]]
162
+ @o.date.y.should == 2
163
+ @o.date.m.should == 6
164
+ @o.date = c.new(3, 4)
165
+ @o.save
166
+ MODEL_DB.sqls.last.should include("year = 6")
167
+ MODEL_DB.sqls.last.should include("month = 12")
168
+ end
169
+
170
+ it ":mapping option :composer should return nil if all values are nil" do
171
+ @c.composition :date, :mapping=>[:year, :month, :day]
172
+ @c.new.date.should == nil
173
+ end
174
+
175
+ it ":mapping option :decomposer should set all related fields to nil if nil" do
176
+ @c.composition :date, :mapping=>[:year, :month, :day]
177
+ @o.date = nil
178
+ @o.save
179
+ MODEL_DB.sqls.last.should include("year = NULL")
180
+ MODEL_DB.sqls.last.should include("month = NULL")
181
+ MODEL_DB.sqls.last.should include("day = NULL")
182
+ end
183
+
184
+ it "should work correctly with subclasses" do
185
+ @c.composition :date, :mapping=>[:year, :month, :day]
186
+ c = Class.new(@c)
187
+ o = c.load(:id=>1, :year=>1, :month=>2, :day=>3)
188
+ o.date.should == Date.new(1, 2, 3)
189
+ o.save
190
+ MODEL_DB.sqls.last.should include("year = 1")
191
+ MODEL_DB.sqls.last.should include("month = 2")
192
+ MODEL_DB.sqls.last.should include("day = 3")
193
+ end
194
+ end
@@ -0,0 +1,117 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+ if RUBY_VERSION >= '1.9.0'
3
+ describe "force_encoding plugin" do
4
+ before do
5
+ @c = Class.new(Sequel::Model) do
6
+ end
7
+ @c.columns :id, :x
8
+ @c.plugin :force_encoding, 'UTF-8'
9
+ @e1 = Encoding.find('UTF-8')
10
+ end
11
+
12
+ specify "should force encoding to given encoding on load" do
13
+ s = 'blah'
14
+ s.force_encoding('US-ASCII')
15
+ o = @c.load(:id=>1, :x=>s)
16
+ o.x.should == 'blah'
17
+ o.x.encoding.should == @e1
18
+ end
19
+
20
+ specify "should force encoding to given encoding when setting column values" do
21
+ s = 'blah'
22
+ s.force_encoding('US-ASCII')
23
+ o = @c.new(:x=>s)
24
+ o.x.should == 'blah'
25
+ o.x.encoding.should == @e1
26
+ end
27
+
28
+ specify "should have a forced_encoding class accessor" do
29
+ s = 'blah'
30
+ s.force_encoding('US-ASCII')
31
+ @c.forced_encoding = 'Windows-1258'
32
+ o = @c.load(:id=>1, :x=>s)
33
+ o.x.should == 'blah'
34
+ o.x.encoding.should == Encoding.find('Windows-1258')
35
+ end
36
+
37
+ specify "should not force encoding if forced_encoding is nil" do
38
+ s = 'blah'
39
+ s.force_encoding('US-ASCII')
40
+ @c.forced_encoding = nil
41
+ o = @c.load(:id=>1, :x=>s)
42
+ o.x.should == 'blah'
43
+ o.x.encoding.should == Encoding.find('US-ASCII')
44
+ end
45
+
46
+ specify "should work correctly when subclassing" do
47
+ c = Class.new(@c)
48
+ s = 'blah'
49
+ s.force_encoding('US-ASCII')
50
+ o = c.load(:id=>1, :x=>s)
51
+ o.x.should == 'blah'
52
+ o.x.encoding.should == @e1
53
+
54
+ c.plugin :force_encoding, 'UTF-16LE'
55
+ s = ''
56
+ s.force_encoding('US-ASCII')
57
+ o = c.load(:id=>1, :x=>s)
58
+ o.x.should == ''
59
+ o.x.encoding.should == Encoding.find('UTF-16LE')
60
+
61
+ @c.plugin :force_encoding, 'UTF-32LE'
62
+ s = ''
63
+ s.force_encoding('US-ASCII')
64
+ o = @c.load(:id=>1, :x=>s)
65
+ o.x.should == ''
66
+ o.x.encoding.should == Encoding.find('UTF-32LE')
67
+
68
+ s = ''
69
+ s.force_encoding('US-ASCII')
70
+ o = c.load(:id=>1, :x=>s)
71
+ o.x.should == ''
72
+ o.x.encoding.should == Encoding.find('UTF-16LE')
73
+ end
74
+
75
+ specify "should work when saving new model instances" do
76
+ o = @c.new
77
+ @c.dataset = ds = MODEL_DB[:a]
78
+ def ds.first
79
+ s = 'blah'
80
+ s.force_encoding('US-ASCII')
81
+ {:id=>1, :x=>s}
82
+ end
83
+ o.save
84
+ o.x.should == 'blah'
85
+ o.x.encoding.should == @e1
86
+ end
87
+
88
+ specify "should work when refreshing model instances" do
89
+ o = @c.load(:id=>1, :x=>'as')
90
+ @c.dataset = ds = MODEL_DB[:a]
91
+ def ds.first
92
+ s = 'blah'
93
+ s.force_encoding('US-ASCII')
94
+ {:id=>1, :x=>s}
95
+ end
96
+ o.refresh
97
+ o.x.should == 'blah'
98
+ o.x.encoding.should == @e1
99
+ end
100
+
101
+ specify "should work when used with the identity_map plugin if the identity_map plugin is setup first" do
102
+ @c = Class.new(Sequel::Model) do
103
+ end
104
+ @c.columns :id, :x
105
+ @c.plugin :identity_map
106
+ @c.plugin :force_encoding, 'UTF-8'
107
+ @c.with_identity_map do
108
+ o = @c.load(:id=>1)
109
+ s = 'blah'
110
+ s.force_encoding('US-ASCII')
111
+ @c.load(:id=>1, :x=>s)
112
+ o.x.should == 'blah'
113
+ o.x.encoding.should == @e1
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,470 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe "Model hooks" do
4
+ before do
5
+ MODEL_DB.reset
6
+ end
7
+
8
+ specify "should be definable using a block" do
9
+ $adds = []
10
+ c = Class.new(Sequel::Model)
11
+ c.class_eval do
12
+ before_save {$adds << 'hi'}
13
+ end
14
+
15
+ c.new.before_save
16
+ $adds.should == ['hi']
17
+ end
18
+
19
+ specify "should be definable using a method name" do
20
+ $adds = []
21
+ c = Class.new(Sequel::Model)
22
+ c.class_eval do
23
+ def bye; $adds << 'bye'; end
24
+ before_save :bye
25
+ end
26
+
27
+ c.new.before_save
28
+ $adds.should == ['bye']
29
+ end
30
+
31
+ specify "should be additive" do
32
+ $adds = []
33
+ c = Class.new(Sequel::Model)
34
+ c.class_eval do
35
+ after_save {$adds << 'hyiyie'}
36
+ after_save {$adds << 'byiyie'}
37
+ end
38
+
39
+ c.new.after_save
40
+ $adds.should == ['hyiyie', 'byiyie']
41
+ end
42
+
43
+ specify "before hooks should run in reverse order" do
44
+ $adds = []
45
+ c = Class.new(Sequel::Model)
46
+ c.class_eval do
47
+ before_save {$adds << 'hyiyie'}
48
+ before_save {$adds << 'byiyie'}
49
+ end
50
+
51
+ c.new.before_save
52
+ $adds.should == ['byiyie', 'hyiyie']
53
+ end
54
+
55
+ specify "should not be additive if the method or tag already exists" do
56
+ $adds = []
57
+ c = Class.new(Sequel::Model)
58
+ c.class_eval do
59
+ def bye; $adds << 'bye'; end
60
+ before_save :bye
61
+ before_save :bye
62
+ end
63
+
64
+ c.new.before_save
65
+ $adds.should == ['bye']
66
+
67
+ $adds = []
68
+ d = Class.new(Sequel::Model)
69
+ d.class_eval do
70
+ before_save(:bye){$adds << 'hyiyie'}
71
+ before_save(:bye){$adds << 'byiyie'}
72
+ end
73
+
74
+ d.new.before_save
75
+ $adds.should == ['byiyie']
76
+
77
+ $adds = []
78
+ e = Class.new(Sequel::Model)
79
+ e.class_eval do
80
+ def bye; $adds << 'bye'; end
81
+ before_save :bye
82
+ before_save(:bye){$adds << 'byiyie'}
83
+ end
84
+
85
+ e.new.before_save
86
+ $adds.should == ['byiyie']
87
+
88
+ $adds = []
89
+ e = Class.new(Sequel::Model)
90
+ e.class_eval do
91
+ def bye; $adds << 'bye'; end
92
+ before_save(:bye){$adds << 'byiyie'}
93
+ before_save :bye
94
+ end
95
+
96
+ e.new.before_save
97
+ $adds.should == ['bye']
98
+ end
99
+
100
+ specify "should be inheritable" do
101
+ # pending
102
+
103
+ $adds = []
104
+ a = Class.new(Sequel::Model)
105
+ a.class_eval do
106
+ after_save {$adds << '123'}
107
+ end
108
+
109
+ b = Class.new(a)
110
+ b.class_eval do
111
+ after_save {$adds << '456'}
112
+ after_save {$adds << '789'}
113
+ end
114
+
115
+ b.new.after_save
116
+ $adds.should == ['123', '456', '789']
117
+ end
118
+
119
+ specify "should be overridable in descendant classes" do
120
+ $adds = []
121
+ a = Class.new(Sequel::Model)
122
+ a.class_eval do
123
+ before_save {$adds << '123'}
124
+ end
125
+
126
+ b = Class.new(a)
127
+ b.class_eval do
128
+ def before_save; $adds << '456'; end
129
+ end
130
+
131
+ a.new.before_save
132
+ $adds.should == ['123']
133
+ $adds = []
134
+ b.new.before_save
135
+ $adds.should == ['456']
136
+ end
137
+
138
+ specify "should stop processing if a hook returns false" do
139
+ $flag = true
140
+ $adds = []
141
+
142
+ a = Class.new(Sequel::Model)
143
+ a.class_eval do
144
+ after_save {$adds << 'blah'; $flag}
145
+ after_save {$adds << 'cruel'}
146
+ end
147
+
148
+ a.new.after_save
149
+ $adds.should == ['blah', 'cruel']
150
+
151
+ # chain should not break on nil
152
+ $adds = []
153
+ $flag = nil
154
+ a.new.after_save
155
+ $adds.should == ['blah', 'cruel']
156
+
157
+ $adds = []
158
+ $flag = false
159
+ a.new.after_save
160
+ $adds.should == ['blah']
161
+
162
+ b = Class.new(a)
163
+ b.class_eval do
164
+ after_save {$adds << 'mau'}
165
+ end
166
+
167
+ $adds = []
168
+ b.new.after_save
169
+ $adds.should == ['blah']
170
+ end
171
+ end
172
+
173
+ describe "Model#after_initialize" do
174
+ specify "should be called after initialization" do
175
+ $values1 = nil
176
+ $reached_after_initialized = false
177
+
178
+ a = Class.new(Sequel::Model)
179
+ a.class_eval do
180
+ columns :x, :y
181
+ after_initialize do
182
+ $values1 = @values.clone
183
+ $reached_after_initialized = true
184
+ end
185
+ end
186
+
187
+ a.new(:x => 1, :y => 2)
188
+ $values1.should == {:x => 1, :y => 2}
189
+ $reached_after_initialized.should == true
190
+ end
191
+ end
192
+
193
+ describe "Model#before_create && Model#after_create" do
194
+ before do
195
+ MODEL_DB.reset
196
+
197
+ @c = Class.new(Sequel::Model(:items))
198
+ @c.class_eval do
199
+ columns :x
200
+ no_primary_key
201
+
202
+ after_create {MODEL_DB << "BLAH after"}
203
+ end
204
+ end
205
+
206
+ specify "should be called around new record creation" do
207
+ @c.before_create {MODEL_DB << "BLAH before"}
208
+ @c.create(:x => 2)
209
+ MODEL_DB.sqls.should == [
210
+ 'BLAH before',
211
+ 'INSERT INTO items (x) VALUES (2)',
212
+ 'BLAH after'
213
+ ]
214
+ end
215
+
216
+ specify ".create should cancel the save and raise an error if before_create returns false and raise_on_save_failure is true" do
217
+ @c.before_create{false}
218
+ proc{@c.load(:id => 2233).save}.should_not raise_error(Sequel::ValidationFailed)
219
+ proc{@c.create(:x => 2)}.should raise_error(Sequel::BeforeHookFailed)
220
+ MODEL_DB.sqls.should == []
221
+ end
222
+
223
+ specify ".create should cancel the save and return nil if before_create returns false and raise_on_save_failure is false" do
224
+ @c.before_create{false}
225
+ @c.raise_on_save_failure = false
226
+ @c.create(:x => 2).should == nil
227
+ MODEL_DB.sqls.should == []
228
+ end
229
+ end
230
+
231
+ describe "Model#before_update && Model#after_update" do
232
+ before do
233
+ MODEL_DB.reset
234
+
235
+ @c = Class.new(Sequel::Model(:items))
236
+ @c.class_eval do
237
+ after_update {MODEL_DB << "BLAH after"}
238
+ end
239
+ end
240
+
241
+ specify "should be called around record update" do
242
+ @c.before_update {MODEL_DB << "BLAH before"}
243
+ m = @c.load(:id => 2233, :x=>123)
244
+ m.save
245
+ MODEL_DB.sqls.should == [
246
+ 'BLAH before',
247
+ 'UPDATE items SET x = 123 WHERE (id = 2233)',
248
+ 'BLAH after'
249
+ ]
250
+ end
251
+
252
+ specify "#save should cancel the save and raise an error if before_update returns false and raise_on_save_failure is true" do
253
+ @c.before_update{false}
254
+ proc{@c.load(:id => 2233).save}.should_not raise_error(Sequel::ValidationFailed)
255
+ proc{@c.load(:id => 2233).save}.should raise_error(Sequel::BeforeHookFailed)
256
+ MODEL_DB.sqls.should == []
257
+ end
258
+
259
+ specify "#save should cancel the save and return nil if before_update returns false and raise_on_save_failure is false" do
260
+ @c.before_update{false}
261
+ @c.raise_on_save_failure = false
262
+ @c.load(:id => 2233).save.should == nil
263
+ MODEL_DB.sqls.should == []
264
+ end
265
+ end
266
+
267
+ describe "Model#before_save && Model#after_save" do
268
+ before do
269
+ MODEL_DB.reset
270
+
271
+ @c = Class.new(Sequel::Model(:items))
272
+ @c.class_eval do
273
+ columns :x
274
+ after_save {MODEL_DB << "BLAH after"}
275
+ end
276
+ end
277
+
278
+ specify "should be called around record update" do
279
+ @c.before_save {MODEL_DB << "BLAH before"}
280
+ m = @c.load(:id => 2233, :x=>123)
281
+ m.save
282
+ MODEL_DB.sqls.should == [
283
+ 'BLAH before',
284
+ 'UPDATE items SET x = 123 WHERE (id = 2233)',
285
+ 'BLAH after'
286
+ ]
287
+ end
288
+
289
+ specify "should be called around record creation" do
290
+ @c.before_save {MODEL_DB << "BLAH before"}
291
+ @c.no_primary_key
292
+ @c.create(:x => 2)
293
+ MODEL_DB.sqls.should == [
294
+ 'BLAH before',
295
+ 'INSERT INTO items (x) VALUES (2)',
296
+ 'BLAH after'
297
+ ]
298
+ end
299
+
300
+ specify "#save should cancel the save and raise an error if before_save returns false and raise_on_save_failure is true" do
301
+ @c.before_save{false}
302
+ proc{@c.load(:id => 2233).save}.should_not raise_error(Sequel::ValidationFailed)
303
+ proc{@c.load(:id => 2233).save}.should raise_error(Sequel::BeforeHookFailed)
304
+ MODEL_DB.sqls.should == []
305
+ end
306
+
307
+ specify "#save should cancel the save and return nil if before_save returns false and raise_on_save_failure is false" do
308
+ @c.before_save{false}
309
+ @c.raise_on_save_failure = false
310
+ @c.load(:id => 2233).save.should == nil
311
+ MODEL_DB.sqls.should == []
312
+ end
313
+ end
314
+
315
+ describe "Model#before_destroy && Model#after_destroy" do
316
+ before do
317
+ MODEL_DB.reset
318
+
319
+ @c = Class.new(Sequel::Model(:items))
320
+ @c.class_eval do
321
+ after_destroy {MODEL_DB << "BLAH after"}
322
+
323
+ def delete
324
+ MODEL_DB << "DELETE BLAH"
325
+ end
326
+ end
327
+ end
328
+
329
+ specify "should be called around record destruction" do
330
+ @c.before_destroy {MODEL_DB << "BLAH before"}
331
+ m = @c.load(:id => 2233)
332
+ m.destroy
333
+ MODEL_DB.sqls.should == [
334
+ 'BLAH before',
335
+ 'DELETE BLAH',
336
+ 'BLAH after'
337
+ ]
338
+ end
339
+
340
+ specify "#destroy should cancel the destroy and raise an error if before_destroy returns false and raise_on_save_failure is true" do
341
+ @c.before_destroy{false}
342
+ proc{@c.load(:id => 2233).destroy}.should raise_error(Sequel::BeforeHookFailed)
343
+ MODEL_DB.sqls.should == []
344
+ end
345
+
346
+ specify "#destroy should cancel the destroy and return nil if before_destroy returns false and raise_on_save_failure is false" do
347
+ @c.before_destroy{false}
348
+ @c.raise_on_save_failure = false
349
+ @c.load(:id => 2233).destroy.should == nil
350
+ MODEL_DB.sqls.should == []
351
+ end
352
+ end
353
+
354
+ describe "Model#before_validation && Model#after_validation" do
355
+ before do
356
+ MODEL_DB.reset
357
+
358
+ @c = Class.new(Sequel::Model(:items))
359
+ @c.class_eval do
360
+ after_validation{MODEL_DB << "BLAH after"}
361
+
362
+ def self.validate(o)
363
+ o.errors[:id] << 'not valid' unless o[:id] == 2233
364
+ end
365
+ columns :id
366
+ end
367
+ end
368
+
369
+ specify "should be called around validation" do
370
+ @c.before_validation{MODEL_DB << "BLAH before"}
371
+ m = @c.load(:id => 2233)
372
+ m.should be_valid
373
+ MODEL_DB.sqls.should == ['BLAH before', 'BLAH after']
374
+
375
+ MODEL_DB.sqls.clear
376
+ m = @c.load(:id => 22)
377
+ m.should_not be_valid
378
+ MODEL_DB.sqls.should == ['BLAH before', 'BLAH after']
379
+ end
380
+
381
+ specify "should be called when calling save" do
382
+ @c.before_validation{MODEL_DB << "BLAH before"}
383
+ m = @c.load(:id => 2233, :x=>123)
384
+ m.save.should == m
385
+ MODEL_DB.sqls.should == ['BLAH before', 'BLAH after', 'UPDATE items SET x = 123 WHERE (id = 2233)']
386
+
387
+ MODEL_DB.sqls.clear
388
+ m = @c.load(:id => 22)
389
+ m.raise_on_save_failure = false
390
+ m.save.should == nil
391
+ MODEL_DB.sqls.should == ['BLAH before', 'BLAH after']
392
+ end
393
+
394
+ specify "#save should cancel the save and raise an error if before_validation returns false and raise_on_save_failure is true" do
395
+ @c.before_validation{false}
396
+ proc{@c.load(:id => 2233).save}.should_not raise_error(Sequel::ValidationFailed)
397
+ proc{@c.load(:id => 2233).save}.should raise_error(Sequel::BeforeHookFailed)
398
+ MODEL_DB.sqls.should == []
399
+ end
400
+
401
+ specify "#save should cancel the save and return nil if before_validation returns false and raise_on_save_failure is false" do
402
+ @c.before_validation{false}
403
+ @c.raise_on_save_failure = false
404
+ @c.load(:id => 2233).save.should == nil
405
+ MODEL_DB.sqls.should == []
406
+ end
407
+ end
408
+
409
+ describe "Model.has_hooks?" do
410
+ before do
411
+ @c = Class.new(Sequel::Model(:items))
412
+ end
413
+
414
+ specify "should return false if no hooks are defined" do
415
+ @c.has_hooks?(:before_save).should be_false
416
+ end
417
+
418
+ specify "should return true if hooks are defined" do
419
+ @c.before_save {'blah'}
420
+ @c.has_hooks?(:before_save).should be_true
421
+ end
422
+
423
+ specify "should return true if hooks are inherited" do
424
+ @d = Class.new(@c)
425
+ @d.has_hooks?(:before_save).should be_false
426
+ end
427
+ end
428
+
429
+ describe "Model#add_hook_type" do
430
+ before do
431
+ class Foo < Sequel::Model(:items)
432
+ add_hook_type :before_bar, :after_bar
433
+
434
+ def bar
435
+ return :b if before_bar == false
436
+ return :a if after_bar == false
437
+ true
438
+ end
439
+ end
440
+ @f = Class.new(Foo)
441
+ end
442
+
443
+ specify "should have before_bar and after_bar class methods" do
444
+ @f.should respond_to(:before_bar)
445
+ @f.should respond_to(:before_bar)
446
+ end
447
+
448
+ specify "should have before_bar and after_bar instance methods" do
449
+ @f.new.should respond_to(:before_bar)
450
+ @f.new.should respond_to(:before_bar)
451
+ end
452
+
453
+ specify "it should return true for bar when before_bar and after_bar hooks are returing true" do
454
+ a = 1
455
+ @f.before_bar { a += 1}
456
+ @f.new.bar.should be_true
457
+ a.should == 2
458
+ @f.after_bar { a *= 2}
459
+ @f.new.bar.should be_true
460
+ a.should == 6
461
+ end
462
+
463
+ specify "it should return nil for bar when before_bar and after_bar hooks are returing false" do
464
+ @f.new.bar.should be_true
465
+ @f.after_bar { false }
466
+ @f.new.bar.should == :a
467
+ @f.before_bar { false }
468
+ @f.new.bar.should == :b
469
+ end
470
+ end