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.
- data/README.rdoc +652 -0
- data/VERSION.yml +4 -0
- data/bin/sequel +104 -0
- data/lib/sequel.rb +1 -0
- data/lib/sequel/adapters/ado.rb +85 -0
- data/lib/sequel/adapters/db2.rb +132 -0
- data/lib/sequel/adapters/dbi.rb +101 -0
- data/lib/sequel/adapters/do.rb +197 -0
- data/lib/sequel/adapters/do/mysql.rb +38 -0
- data/lib/sequel/adapters/do/postgres.rb +92 -0
- data/lib/sequel/adapters/do/sqlite.rb +31 -0
- data/lib/sequel/adapters/firebird.rb +307 -0
- data/lib/sequel/adapters/informix.rb +75 -0
- data/lib/sequel/adapters/jdbc.rb +485 -0
- data/lib/sequel/adapters/jdbc/h2.rb +62 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +56 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +23 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +101 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +43 -0
- data/lib/sequel/adapters/mysql.rb +370 -0
- data/lib/sequel/adapters/odbc.rb +184 -0
- data/lib/sequel/adapters/openbase.rb +57 -0
- data/lib/sequel/adapters/oracle.rb +140 -0
- data/lib/sequel/adapters/postgres.rb +453 -0
- data/lib/sequel/adapters/shared/mssql.rb +93 -0
- data/lib/sequel/adapters/shared/mysql.rb +341 -0
- data/lib/sequel/adapters/shared/oracle.rb +62 -0
- data/lib/sequel/adapters/shared/postgres.rb +743 -0
- data/lib/sequel/adapters/shared/progress.rb +34 -0
- data/lib/sequel/adapters/shared/sqlite.rb +263 -0
- data/lib/sequel/adapters/sqlite.rb +243 -0
- data/lib/sequel/adapters/utils/date_format.rb +21 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +75 -0
- data/lib/sequel/adapters/utils/unsupported.rb +62 -0
- data/lib/sequel/connection_pool.rb +258 -0
- data/lib/sequel/core.rb +204 -0
- data/lib/sequel/core_sql.rb +185 -0
- data/lib/sequel/database.rb +687 -0
- data/lib/sequel/database/schema_generator.rb +324 -0
- data/lib/sequel/database/schema_methods.rb +164 -0
- data/lib/sequel/database/schema_sql.rb +324 -0
- data/lib/sequel/dataset.rb +422 -0
- data/lib/sequel/dataset/convenience.rb +237 -0
- data/lib/sequel/dataset/prepared_statements.rb +220 -0
- data/lib/sequel/dataset/sql.rb +1105 -0
- data/lib/sequel/deprecated.rb +529 -0
- data/lib/sequel/exceptions.rb +44 -0
- data/lib/sequel/extensions/blank.rb +42 -0
- data/lib/sequel/extensions/inflector.rb +288 -0
- data/lib/sequel/extensions/pagination.rb +96 -0
- data/lib/sequel/extensions/pretty_table.rb +78 -0
- data/lib/sequel/extensions/query.rb +48 -0
- data/lib/sequel/extensions/string_date_time.rb +47 -0
- data/lib/sequel/metaprogramming.rb +44 -0
- data/lib/sequel/migration.rb +212 -0
- data/lib/sequel/model.rb +142 -0
- data/lib/sequel/model/association_reflection.rb +263 -0
- data/lib/sequel/model/associations.rb +1024 -0
- data/lib/sequel/model/base.rb +911 -0
- data/lib/sequel/model/deprecated.rb +188 -0
- data/lib/sequel/model/deprecated_hooks.rb +103 -0
- data/lib/sequel/model/deprecated_inflector.rb +335 -0
- data/lib/sequel/model/deprecated_validations.rb +384 -0
- data/lib/sequel/model/errors.rb +37 -0
- data/lib/sequel/model/exceptions.rb +7 -0
- data/lib/sequel/model/inflections.rb +230 -0
- data/lib/sequel/model/plugins.rb +74 -0
- data/lib/sequel/object_graph.rb +230 -0
- data/lib/sequel/plugins/caching.rb +122 -0
- data/lib/sequel/plugins/hook_class_methods.rb +122 -0
- data/lib/sequel/plugins/schema.rb +53 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
- data/lib/sequel/plugins/validation_class_methods.rb +373 -0
- data/lib/sequel/sql.rb +854 -0
- data/lib/sequel/version.rb +11 -0
- data/lib/sequel_core.rb +1 -0
- data/lib/sequel_model.rb +1 -0
- data/spec/adapters/ado_spec.rb +46 -0
- data/spec/adapters/firebird_spec.rb +376 -0
- data/spec/adapters/informix_spec.rb +96 -0
- data/spec/adapters/mysql_spec.rb +875 -0
- data/spec/adapters/oracle_spec.rb +272 -0
- data/spec/adapters/postgres_spec.rb +692 -0
- data/spec/adapters/spec_helper.rb +10 -0
- data/spec/adapters/sqlite_spec.rb +550 -0
- data/spec/core/connection_pool_spec.rb +526 -0
- data/spec/core/core_ext_spec.rb +156 -0
- data/spec/core/core_sql_spec.rb +528 -0
- data/spec/core/database_spec.rb +1214 -0
- data/spec/core/dataset_spec.rb +3513 -0
- data/spec/core/expression_filters_spec.rb +363 -0
- data/spec/core/migration_spec.rb +261 -0
- data/spec/core/object_graph_spec.rb +280 -0
- data/spec/core/pretty_table_spec.rb +58 -0
- data/spec/core/schema_generator_spec.rb +167 -0
- data/spec/core/schema_spec.rb +778 -0
- data/spec/core/spec_helper.rb +82 -0
- data/spec/core/version_spec.rb +7 -0
- data/spec/extensions/blank_spec.rb +67 -0
- data/spec/extensions/caching_spec.rb +201 -0
- data/spec/extensions/hook_class_methods_spec.rb +470 -0
- data/spec/extensions/inflector_spec.rb +122 -0
- data/spec/extensions/pagination_spec.rb +99 -0
- data/spec/extensions/pretty_table_spec.rb +91 -0
- data/spec/extensions/query_spec.rb +85 -0
- data/spec/extensions/schema_spec.rb +111 -0
- data/spec/extensions/single_table_inheritance_spec.rb +53 -0
- data/spec/extensions/spec_helper.rb +90 -0
- data/spec/extensions/string_date_time_spec.rb +93 -0
- data/spec/extensions/validation_class_methods_spec.rb +1054 -0
- data/spec/integration/dataset_test.rb +160 -0
- data/spec/integration/eager_loader_test.rb +683 -0
- data/spec/integration/prepared_statement_test.rb +130 -0
- data/spec/integration/schema_test.rb +183 -0
- data/spec/integration/spec_helper.rb +75 -0
- data/spec/integration/type_test.rb +96 -0
- data/spec/model/association_reflection_spec.rb +93 -0
- data/spec/model/associations_spec.rb +1780 -0
- data/spec/model/base_spec.rb +494 -0
- data/spec/model/caching_spec.rb +217 -0
- data/spec/model/dataset_methods_spec.rb +78 -0
- data/spec/model/eager_loading_spec.rb +1165 -0
- data/spec/model/hooks_spec.rb +472 -0
- data/spec/model/inflector_spec.rb +126 -0
- data/spec/model/model_spec.rb +588 -0
- data/spec/model/plugins_spec.rb +142 -0
- data/spec/model/record_spec.rb +1243 -0
- data/spec/model/schema_spec.rb +92 -0
- data/spec/model/spec_helper.rb +124 -0
- data/spec/model/validations_spec.rb +1080 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec.opts +0 -0
- data/spec/spec_config.rb.example +10 -0
- 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,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
|