epugh-sequel 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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