epugh-sequel 0.0.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 (134) hide show
  1. data/README.rdoc +652 -0
  2. data/VERSION.yml +4 -0
  3. data/bin/sequel +104 -0
  4. data/lib/sequel.rb +1 -0
  5. data/lib/sequel/adapters/ado.rb +85 -0
  6. data/lib/sequel/adapters/db2.rb +132 -0
  7. data/lib/sequel/adapters/dbi.rb +101 -0
  8. data/lib/sequel/adapters/do.rb +197 -0
  9. data/lib/sequel/adapters/do/mysql.rb +38 -0
  10. data/lib/sequel/adapters/do/postgres.rb +92 -0
  11. data/lib/sequel/adapters/do/sqlite.rb +31 -0
  12. data/lib/sequel/adapters/firebird.rb +307 -0
  13. data/lib/sequel/adapters/informix.rb +75 -0
  14. data/lib/sequel/adapters/jdbc.rb +485 -0
  15. data/lib/sequel/adapters/jdbc/h2.rb +62 -0
  16. data/lib/sequel/adapters/jdbc/mysql.rb +56 -0
  17. data/lib/sequel/adapters/jdbc/oracle.rb +23 -0
  18. data/lib/sequel/adapters/jdbc/postgresql.rb +101 -0
  19. data/lib/sequel/adapters/jdbc/sqlite.rb +43 -0
  20. data/lib/sequel/adapters/mysql.rb +370 -0
  21. data/lib/sequel/adapters/odbc.rb +184 -0
  22. data/lib/sequel/adapters/openbase.rb +57 -0
  23. data/lib/sequel/adapters/oracle.rb +140 -0
  24. data/lib/sequel/adapters/postgres.rb +453 -0
  25. data/lib/sequel/adapters/shared/mssql.rb +93 -0
  26. data/lib/sequel/adapters/shared/mysql.rb +341 -0
  27. data/lib/sequel/adapters/shared/oracle.rb +62 -0
  28. data/lib/sequel/adapters/shared/postgres.rb +743 -0
  29. data/lib/sequel/adapters/shared/progress.rb +34 -0
  30. data/lib/sequel/adapters/shared/sqlite.rb +263 -0
  31. data/lib/sequel/adapters/sqlite.rb +243 -0
  32. data/lib/sequel/adapters/utils/date_format.rb +21 -0
  33. data/lib/sequel/adapters/utils/stored_procedures.rb +75 -0
  34. data/lib/sequel/adapters/utils/unsupported.rb +62 -0
  35. data/lib/sequel/connection_pool.rb +258 -0
  36. data/lib/sequel/core.rb +204 -0
  37. data/lib/sequel/core_sql.rb +185 -0
  38. data/lib/sequel/database.rb +687 -0
  39. data/lib/sequel/database/schema_generator.rb +324 -0
  40. data/lib/sequel/database/schema_methods.rb +164 -0
  41. data/lib/sequel/database/schema_sql.rb +324 -0
  42. data/lib/sequel/dataset.rb +422 -0
  43. data/lib/sequel/dataset/convenience.rb +237 -0
  44. data/lib/sequel/dataset/prepared_statements.rb +220 -0
  45. data/lib/sequel/dataset/sql.rb +1105 -0
  46. data/lib/sequel/deprecated.rb +529 -0
  47. data/lib/sequel/exceptions.rb +44 -0
  48. data/lib/sequel/extensions/blank.rb +42 -0
  49. data/lib/sequel/extensions/inflector.rb +288 -0
  50. data/lib/sequel/extensions/pagination.rb +96 -0
  51. data/lib/sequel/extensions/pretty_table.rb +78 -0
  52. data/lib/sequel/extensions/query.rb +48 -0
  53. data/lib/sequel/extensions/string_date_time.rb +47 -0
  54. data/lib/sequel/metaprogramming.rb +44 -0
  55. data/lib/sequel/migration.rb +212 -0
  56. data/lib/sequel/model.rb +142 -0
  57. data/lib/sequel/model/association_reflection.rb +263 -0
  58. data/lib/sequel/model/associations.rb +1024 -0
  59. data/lib/sequel/model/base.rb +911 -0
  60. data/lib/sequel/model/deprecated.rb +188 -0
  61. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  62. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  63. data/lib/sequel/model/deprecated_validations.rb +384 -0
  64. data/lib/sequel/model/errors.rb +37 -0
  65. data/lib/sequel/model/exceptions.rb +7 -0
  66. data/lib/sequel/model/inflections.rb +230 -0
  67. data/lib/sequel/model/plugins.rb +74 -0
  68. data/lib/sequel/object_graph.rb +230 -0
  69. data/lib/sequel/plugins/caching.rb +122 -0
  70. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  71. data/lib/sequel/plugins/schema.rb +53 -0
  72. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  73. data/lib/sequel/plugins/validation_class_methods.rb +373 -0
  74. data/lib/sequel/sql.rb +854 -0
  75. data/lib/sequel/version.rb +11 -0
  76. data/lib/sequel_core.rb +1 -0
  77. data/lib/sequel_model.rb +1 -0
  78. data/spec/adapters/ado_spec.rb +46 -0
  79. data/spec/adapters/firebird_spec.rb +376 -0
  80. data/spec/adapters/informix_spec.rb +96 -0
  81. data/spec/adapters/mysql_spec.rb +875 -0
  82. data/spec/adapters/oracle_spec.rb +272 -0
  83. data/spec/adapters/postgres_spec.rb +692 -0
  84. data/spec/adapters/spec_helper.rb +10 -0
  85. data/spec/adapters/sqlite_spec.rb +550 -0
  86. data/spec/core/connection_pool_spec.rb +526 -0
  87. data/spec/core/core_ext_spec.rb +156 -0
  88. data/spec/core/core_sql_spec.rb +528 -0
  89. data/spec/core/database_spec.rb +1214 -0
  90. data/spec/core/dataset_spec.rb +3513 -0
  91. data/spec/core/expression_filters_spec.rb +363 -0
  92. data/spec/core/migration_spec.rb +261 -0
  93. data/spec/core/object_graph_spec.rb +280 -0
  94. data/spec/core/pretty_table_spec.rb +58 -0
  95. data/spec/core/schema_generator_spec.rb +167 -0
  96. data/spec/core/schema_spec.rb +778 -0
  97. data/spec/core/spec_helper.rb +82 -0
  98. data/spec/core/version_spec.rb +7 -0
  99. data/spec/extensions/blank_spec.rb +67 -0
  100. data/spec/extensions/caching_spec.rb +201 -0
  101. data/spec/extensions/hook_class_methods_spec.rb +470 -0
  102. data/spec/extensions/inflector_spec.rb +122 -0
  103. data/spec/extensions/pagination_spec.rb +99 -0
  104. data/spec/extensions/pretty_table_spec.rb +91 -0
  105. data/spec/extensions/query_spec.rb +85 -0
  106. data/spec/extensions/schema_spec.rb +111 -0
  107. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  108. data/spec/extensions/spec_helper.rb +90 -0
  109. data/spec/extensions/string_date_time_spec.rb +93 -0
  110. data/spec/extensions/validation_class_methods_spec.rb +1054 -0
  111. data/spec/integration/dataset_test.rb +160 -0
  112. data/spec/integration/eager_loader_test.rb +683 -0
  113. data/spec/integration/prepared_statement_test.rb +130 -0
  114. data/spec/integration/schema_test.rb +183 -0
  115. data/spec/integration/spec_helper.rb +75 -0
  116. data/spec/integration/type_test.rb +96 -0
  117. data/spec/model/association_reflection_spec.rb +93 -0
  118. data/spec/model/associations_spec.rb +1780 -0
  119. data/spec/model/base_spec.rb +494 -0
  120. data/spec/model/caching_spec.rb +217 -0
  121. data/spec/model/dataset_methods_spec.rb +78 -0
  122. data/spec/model/eager_loading_spec.rb +1165 -0
  123. data/spec/model/hooks_spec.rb +472 -0
  124. data/spec/model/inflector_spec.rb +126 -0
  125. data/spec/model/model_spec.rb +588 -0
  126. data/spec/model/plugins_spec.rb +142 -0
  127. data/spec/model/record_spec.rb +1243 -0
  128. data/spec/model/schema_spec.rb +92 -0
  129. data/spec/model/spec_helper.rb +124 -0
  130. data/spec/model/validations_spec.rb +1080 -0
  131. data/spec/rcov.opts +6 -0
  132. data/spec/spec.opts +0 -0
  133. data/spec/spec_config.rb.example +10 -0
  134. metadata +202 -0
@@ -0,0 +1,82 @@
1
+ require 'rubygems'
2
+ unless Object.const_defined?('Sequel')
3
+ $:.unshift(File.join(File.dirname(__FILE__), "../../lib/"))
4
+ require 'sequel/core'
5
+ end
6
+
7
+ Sequel.virtual_row_instance_eval = true
8
+
9
+ module Spec::Example::ExampleMethods
10
+ def deprec
11
+ output = Sequel::Deprecation.output = nil
12
+ begin
13
+ yield
14
+ ensure
15
+ Sequel::Deprecation.output = output
16
+ end
17
+ end
18
+ end
19
+
20
+ module Spec::Example::ExampleGroupMethods
21
+ def deprec_specify(*args, &block)
22
+ specify(*args) do
23
+ output = Sequel::Deprecation.output
24
+ Sequel::Deprecation.output = nil
25
+ begin
26
+ instance_eval(&block)
27
+ ensure
28
+ Sequel::Deprecation.output = output
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ class MockDataset < Sequel::Dataset
35
+ def insert(*args)
36
+ @db.execute insert_sql(*args)
37
+ end
38
+
39
+ def update(*args)
40
+ @db.execute update_sql(*args)
41
+ end
42
+
43
+ def fetch_rows(sql)
44
+ @db.execute(sql)
45
+ yield({:id => 1, :x => 1})
46
+ end
47
+
48
+ def quoted_identifier(c)
49
+ "\"#{c}\""
50
+ end
51
+ end
52
+
53
+ class MockDatabase < Sequel::Database
54
+ @@quote_identifiers = false
55
+ self.identifier_input_method = nil
56
+ self.identifier_output_method = nil
57
+ attr_reader :sqls
58
+
59
+ def execute(sql, opts={})
60
+ @sqls ||= []
61
+ @sqls << sql
62
+ end
63
+
64
+ def reset
65
+ @sqls = []
66
+ end
67
+
68
+ def transaction(opts={}); yield; end
69
+
70
+ def dataset; MockDataset.new(self); end
71
+ end
72
+
73
+ class SchemaDummyDatabase < Sequel::Database
74
+ attr_reader :sqls
75
+ self.identifier_input_method = nil
76
+ self.identifier_output_method = nil
77
+
78
+ def execute(sql, opts={})
79
+ @sqls ||= []
80
+ @sqls << sql
81
+ end
82
+ end
@@ -0,0 +1,7 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ context "Sequel.version" do
4
+ specify "should be in the form X.Y.Z with all being numbers" do
5
+ Sequel.version.should =~ /\A\d+\.\d+\.\d+\z/
6
+ end
7
+ end
@@ -0,0 +1,67 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ context "Object#blank?" do
4
+ specify "it should be true if the object responds true to empty?" do
5
+ [].blank?.should == true
6
+ {}.blank?.should == true
7
+ o = Object.new
8
+ def o.empty?; true; end
9
+ o.blank?.should == true
10
+ end
11
+
12
+ specify "it should be false if the object doesn't respond true to empty?" do
13
+ [2].blank?.should == false
14
+ {1=>2}.blank?.should == false
15
+ Object.new.blank?.should == false
16
+ end
17
+ end
18
+
19
+ context "Numeric#blank?" do
20
+ specify "it should always be false" do
21
+ 1.blank?.should == false
22
+ 0.blank?.should == false
23
+ -1.blank?.should == false
24
+ 1.0.blank?.should == false
25
+ 0.0.blank?.should == false
26
+ -1.0.blank?.should == false
27
+ 10000000000000000.blank?.should == false
28
+ -10000000000000000.blank?.should == false
29
+ 10000000000000000.0.blank?.should == false
30
+ -10000000000000000.0.blank?.should == false
31
+ end
32
+ end
33
+
34
+ context "NilClass#blank?" do
35
+ specify "it should always be true" do
36
+ nil.blank?.should == true
37
+ end
38
+ end
39
+
40
+ context "TrueClass#blank?" do
41
+ specify "it should always be false" do
42
+ true.blank?.should == false
43
+ end
44
+ end
45
+
46
+ context "FalseClass#blank?" do
47
+ specify "it should always be true" do
48
+ false.blank?.should == true
49
+ end
50
+ end
51
+
52
+ context "String#blank?" do
53
+ specify "it should be true if the string is empty" do
54
+ ''.blank?.should == true
55
+ end
56
+ specify "it should be true if the string is composed of just whitespace" do
57
+ ' '.blank?.should == true
58
+ "\r\n\t".blank?.should == true
59
+ (' '*4000).blank?.should == true
60
+ ("\r\n\t"*4000).blank?.should == true
61
+ end
62
+ specify "it should be false if the string has any non whitespace characters" do
63
+ '1'.blank?.should == false
64
+ ("\r\n\t"*4000 + 'a').blank?.should == false
65
+ ("\r\na\t"*4000).blank?.should == false
66
+ end
67
+ end
@@ -0,0 +1,201 @@
1
+ require File.join(File.dirname(__FILE__), "spec_helper")
2
+
3
+ describe Sequel::Model, "caching" do
4
+ before do
5
+ MODEL_DB.reset
6
+
7
+ @cache_class = Class.new(Hash) do
8
+ attr_accessor :ttl
9
+ def set(k, v, ttl); self[k] = v; @ttl = ttl; end
10
+ def get(k); self[k]; end
11
+ end
12
+ cache = @cache_class.new
13
+ @cache = cache
14
+
15
+ @c = Class.new(Sequel::Model(:items))
16
+ @c.class_eval do
17
+ plugin :caching, cache
18
+ def self.name; 'Item' end
19
+
20
+ columns :name, :id
21
+ end
22
+
23
+ $cache_dataset_row = {:name => 'sharon', :id => 1}
24
+ @dataset = @c.dataset
25
+ $sqls = []
26
+ @dataset.extend(Module.new {
27
+ def fetch_rows(sql)
28
+ $sqls << sql
29
+ yield $cache_dataset_row
30
+ end
31
+
32
+ def update(values)
33
+ $sqls << update_sql(values)
34
+ $cache_dataset_row.merge!(values)
35
+ end
36
+
37
+ def delete
38
+ $sqls << delete_sql
39
+ end
40
+ })
41
+ @c2 = Class.new(@c) do
42
+ def self.name; 'SubItem' end
43
+ end
44
+ end
45
+
46
+ it "should set the model's cache store" do
47
+ @c.cache_store.should be(@cache)
48
+ @c2.cache_store.should be(@cache)
49
+ end
50
+
51
+ it "should have a default ttl of 3600" do
52
+ @c.cache_ttl.should == 3600
53
+ @c2.cache_ttl.should == 3600
54
+ end
55
+
56
+ it "should take a ttl option" do
57
+ @c.plugin :caching, @cache, :ttl => 1234
58
+ @c.cache_ttl.should == 1234
59
+ Class.new(@c).cache_ttl.should == 1234
60
+ end
61
+
62
+ it "should offer a set_cache_ttl method for setting the ttl" do
63
+ @c.cache_ttl.should == 3600
64
+ @c.set_cache_ttl 1234
65
+ @c.cache_ttl.should == 1234
66
+ Class.new(@c).cache_ttl.should == 1234
67
+ end
68
+
69
+ it "should generate a cache key appropriate to the class" do
70
+ m = @c.new
71
+ m.values[:id] = 1
72
+ m.cache_key.should == "#{m.class}:1"
73
+ m = @c2.new
74
+ m.values[:id] = 1
75
+ m.cache_key.should == "#{m.class}:1"
76
+
77
+ # custom primary key
78
+ @c.set_primary_key :ttt
79
+ m = @c.new
80
+ m.values[:ttt] = 333
81
+ m.cache_key.should == "#{m.class}:333"
82
+ c = Class.new(@c)
83
+ m = c.new
84
+ m.values[:ttt] = 333
85
+ m.cache_key.should == "#{m.class}:333"
86
+
87
+ # composite primary key
88
+ @c.set_primary_key [:a, :b, :c]
89
+ m = @c.new
90
+ m.values[:a] = 123
91
+ m.values[:c] = 456
92
+ m.values[:b] = 789
93
+ m.cache_key.should == "#{m.class}:123,789,456"
94
+ c = Class.new(@c)
95
+ m = c.new
96
+ m.values[:a] = 123
97
+ m.values[:c] = 456
98
+ m.values[:b] = 789
99
+ m.cache_key.should == "#{m.class}:123,789,456"
100
+ end
101
+
102
+ it "should raise error if attempting to generate cache_key and primary key value is null" do
103
+ m = @c.new
104
+ proc {m.cache_key}.should raise_error(Sequel::Error)
105
+ m.values[:id] = 1
106
+ proc {m.cache_key}.should_not raise_error(Sequel::Error)
107
+
108
+ m = @c2.new
109
+ proc {m.cache_key}.should raise_error(Sequel::Error)
110
+ m.values[:id] = 1
111
+ proc {m.cache_key}.should_not raise_error(Sequel::Error)
112
+ end
113
+
114
+ it "should not raise error if trying to save a new record" do
115
+ proc {@c.new(:name=>'blah').save}.should_not raise_error
116
+ proc {@c.create(:name=>'blah')}.should_not raise_error
117
+ proc {@c2.new(:name=>'blah').save}.should_not raise_error
118
+ proc {@c2.create(:name=>'blah')}.should_not raise_error
119
+ end
120
+
121
+ it "should set the cache when reading from the database" do
122
+ $sqls.should == []
123
+ @cache.should be_empty
124
+
125
+ m = @c[1]
126
+ $sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
127
+ m.values.should == $cache_dataset_row
128
+ @cache[m.cache_key].should == m
129
+ m2 = @c[1]
130
+ $sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
131
+ m2.should == m
132
+ m2.values.should == $cache_dataset_row
133
+
134
+ $sqls.clear
135
+ m = @c2[1]
136
+ $sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
137
+ m.values.should == $cache_dataset_row
138
+ @cache[m.cache_key].should == m
139
+ m2 = @c2[1]
140
+ $sqls.should == ['SELECT * FROM items WHERE (id = 1) LIMIT 1']
141
+ m2.should == m
142
+ m2.values.should == $cache_dataset_row
143
+ end
144
+
145
+ it "should delete the cache when writing to the database" do
146
+ m = @c[1]
147
+ @cache[m.cache_key].should == m
148
+ m.name = 'hey'
149
+ m.save
150
+ @cache.has_key?(m.cache_key).should be_false
151
+ $sqls.last.should == "UPDATE items SET name = 'hey', id = 1 WHERE (id = 1)"
152
+
153
+ m = @c2[1]
154
+ @cache[m.cache_key].should == m
155
+ m.name = 'hey'
156
+ m.save
157
+ @cache.has_key?(m.cache_key).should be_false
158
+ $sqls.last.should == "UPDATE items SET name = 'hey', id = 1 WHERE (id = 1)"
159
+ end
160
+
161
+ it "should delete the cache when deleting the record" do
162
+ m = @c[1]
163
+ @cache[m.cache_key].should == m
164
+ m.delete
165
+ @cache.has_key?(m.cache_key).should be_false
166
+ $sqls.last.should == "DELETE FROM items WHERE (id = 1)"
167
+
168
+ m = @c2[1]
169
+ @cache[m.cache_key].should == m
170
+ m.delete
171
+ @cache.has_key?(m.cache_key).should be_false
172
+ $sqls.last.should == "DELETE FROM items WHERE (id = 1)"
173
+ end
174
+
175
+ it "should support #[] as a shortcut to #find with hash" do
176
+ m = @c[:id => 3]
177
+ @cache[m.cache_key].should be_nil
178
+ $sqls.last.should == "SELECT * FROM items WHERE (id = 3) LIMIT 1"
179
+ m = @c[1]
180
+ @cache[m.cache_key].should == m
181
+ $sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
182
+ "SELECT * FROM items WHERE (id = 1) LIMIT 1"]
183
+ @c[:id => 4]
184
+ $sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
185
+ "SELECT * FROM items WHERE (id = 1) LIMIT 1", \
186
+ "SELECT * FROM items WHERE (id = 4) LIMIT 1"]
187
+
188
+ $sqls.clear
189
+ m = @c2[:id => 3]
190
+ @cache[m.cache_key].should be_nil
191
+ $sqls.last.should == "SELECT * FROM items WHERE (id = 3) LIMIT 1"
192
+ m = @c2[1]
193
+ @cache[m.cache_key].should == m
194
+ $sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
195
+ "SELECT * FROM items WHERE (id = 1) LIMIT 1"]
196
+ @c2[:id => 4]
197
+ $sqls.should == ["SELECT * FROM items WHERE (id = 3) LIMIT 1", \
198
+ "SELECT * FROM items WHERE (id = 1) LIMIT 1", \
199
+ "SELECT * FROM items WHERE (id = 4) LIMIT 1"]
200
+ end
201
+ 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
+ setup 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
+ setup 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)
244
+ m.save
245
+ MODEL_DB.sqls.should == [
246
+ 'BLAH before',
247
+ 'UPDATE items SET id = 2233 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
+ setup 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)
281
+ m.save
282
+ MODEL_DB.sqls.should == [
283
+ 'BLAH before',
284
+ 'UPDATE items SET id = 2233 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
+ setup 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
+ setup 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)
384
+ m.save.should == m
385
+ MODEL_DB.sqls.should == ['BLAH before', 'BLAH after', 'UPDATE items SET id = 2233 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
+ setup 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
+ setup 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