sequel 3.28.0 → 3.29.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +119 -3
- data/Rakefile +5 -3
- data/bin/sequel +1 -5
- data/doc/model_hooks.rdoc +9 -1
- data/doc/opening_databases.rdoc +49 -40
- data/doc/prepared_statements.rdoc +27 -6
- data/doc/release_notes/3.28.0.txt +2 -2
- data/doc/release_notes/3.29.0.txt +459 -0
- data/doc/sharding.rdoc +7 -1
- data/doc/testing.rdoc +18 -9
- data/doc/transactions.rdoc +41 -1
- data/lib/sequel/adapters/ado.rb +28 -17
- data/lib/sequel/adapters/ado/mssql.rb +18 -6
- data/lib/sequel/adapters/amalgalite.rb +11 -7
- data/lib/sequel/adapters/db2.rb +122 -70
- data/lib/sequel/adapters/dbi.rb +15 -15
- data/lib/sequel/adapters/do.rb +5 -36
- data/lib/sequel/adapters/do/mysql.rb +0 -5
- data/lib/sequel/adapters/do/postgres.rb +0 -5
- data/lib/sequel/adapters/do/sqlite.rb +0 -5
- data/lib/sequel/adapters/firebird.rb +3 -6
- data/lib/sequel/adapters/ibmdb.rb +24 -16
- data/lib/sequel/adapters/informix.rb +2 -4
- data/lib/sequel/adapters/jdbc.rb +47 -11
- data/lib/sequel/adapters/jdbc/as400.rb +5 -24
- data/lib/sequel/adapters/jdbc/db2.rb +0 -5
- data/lib/sequel/adapters/jdbc/derby.rb +217 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
- data/lib/sequel/adapters/jdbc/h2.rb +10 -12
- data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
- data/lib/sequel/adapters/jdbc/informix.rb +0 -5
- data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -10
- data/lib/sequel/adapters/jdbc/oracle.rb +70 -3
- data/lib/sequel/adapters/jdbc/postgresql.rb +0 -11
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
- data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
- data/lib/sequel/adapters/jdbc/transactions.rb +56 -7
- data/lib/sequel/adapters/mock.rb +315 -0
- data/lib/sequel/adapters/mysql.rb +64 -51
- data/lib/sequel/adapters/mysql2.rb +15 -9
- data/lib/sequel/adapters/odbc.rb +13 -6
- data/lib/sequel/adapters/odbc/db2.rb +0 -4
- data/lib/sequel/adapters/odbc/mssql.rb +0 -5
- data/lib/sequel/adapters/openbase.rb +2 -4
- data/lib/sequel/adapters/oracle.rb +333 -51
- data/lib/sequel/adapters/postgres.rb +80 -27
- data/lib/sequel/adapters/shared/access.rb +0 -6
- data/lib/sequel/adapters/shared/db2.rb +13 -15
- data/lib/sequel/adapters/shared/firebird.rb +6 -6
- data/lib/sequel/adapters/shared/mssql.rb +23 -18
- data/lib/sequel/adapters/shared/mysql.rb +6 -6
- data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +185 -30
- data/lib/sequel/adapters/shared/postgres.rb +35 -18
- data/lib/sequel/adapters/shared/progress.rb +0 -6
- data/lib/sequel/adapters/shared/sqlite.rb +116 -37
- data/lib/sequel/adapters/sqlite.rb +16 -8
- data/lib/sequel/adapters/swift.rb +5 -5
- data/lib/sequel/adapters/swift/mysql.rb +0 -5
- data/lib/sequel/adapters/swift/postgres.rb +0 -5
- data/lib/sequel/adapters/swift/sqlite.rb +6 -4
- data/lib/sequel/adapters/tinytds.rb +13 -10
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -0
- data/lib/sequel/core.rb +40 -0
- data/lib/sequel/database/connecting.rb +1 -2
- data/lib/sequel/database/dataset.rb +3 -3
- data/lib/sequel/database/dataset_defaults.rb +58 -0
- data/lib/sequel/database/misc.rb +62 -2
- data/lib/sequel/database/query.rb +113 -49
- data/lib/sequel/database/schema_methods.rb +7 -2
- data/lib/sequel/dataset/actions.rb +37 -19
- data/lib/sequel/dataset/features.rb +24 -0
- data/lib/sequel/dataset/graph.rb +7 -6
- data/lib/sequel/dataset/misc.rb +11 -3
- data/lib/sequel/dataset/mutation.rb +2 -3
- data/lib/sequel/dataset/prepared_statements.rb +6 -4
- data/lib/sequel/dataset/query.rb +46 -15
- data/lib/sequel/dataset/sql.rb +28 -4
- data/lib/sequel/extensions/named_timezones.rb +5 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
- data/lib/sequel/model.rb +2 -1
- data/lib/sequel/model/associations.rb +115 -33
- data/lib/sequel/model/base.rb +91 -31
- data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
- data/lib/sequel/plugins/dataset_associations.rb +100 -0
- data/lib/sequel/plugins/force_encoding.rb +6 -6
- data/lib/sequel/plugins/identity_map.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +6 -10
- data/lib/sequel/plugins/prepared_statements.rb +12 -1
- data/lib/sequel/plugins/prepared_statements_associations.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +29 -15
- data/lib/sequel/plugins/serialization.rb +6 -1
- data/lib/sequel/plugins/sharding.rb +0 -5
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/typecast_on_load.rb +9 -12
- data/lib/sequel/plugins/update_primary_key.rb +1 -1
- data/lib/sequel/timezones.rb +42 -42
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +29 -29
- data/spec/adapters/mysql_spec.rb +86 -104
- data/spec/adapters/oracle_spec.rb +48 -76
- data/spec/adapters/postgres_spec.rb +98 -33
- data/spec/adapters/spec_helper.rb +0 -5
- data/spec/adapters/sqlite_spec.rb +24 -21
- data/spec/core/connection_pool_spec.rb +9 -15
- data/spec/core/core_sql_spec.rb +20 -31
- data/spec/core/database_spec.rb +491 -227
- data/spec/core/dataset_spec.rb +638 -1051
- data/spec/core/expression_filters_spec.rb +0 -1
- data/spec/core/mock_adapter_spec.rb +378 -0
- data/spec/core/object_graph_spec.rb +48 -114
- data/spec/core/schema_generator_spec.rb +3 -3
- data/spec/core/schema_spec.rb +51 -114
- data/spec/core/spec_helper.rb +3 -90
- data/spec/extensions/class_table_inheritance_spec.rb +1 -1
- data/spec/extensions/dataset_associations_spec.rb +199 -0
- data/spec/extensions/instance_hooks_spec.rb +71 -0
- data/spec/extensions/named_timezones_spec.rb +22 -2
- data/spec/extensions/nested_attributes_spec.rb +3 -0
- data/spec/extensions/schema_spec.rb +1 -1
- data/spec/extensions/serialization_modification_detection_spec.rb +1 -0
- data/spec/extensions/serialization_spec.rb +5 -8
- data/spec/extensions/spec_helper.rb +4 -0
- data/spec/extensions/thread_local_timezones_spec.rb +22 -2
- data/spec/extensions/typecast_on_load_spec.rb +1 -6
- data/spec/integration/associations_test.rb +123 -12
- data/spec/integration/dataset_test.rb +140 -47
- data/spec/integration/eager_loader_test.rb +19 -21
- data/spec/integration/model_test.rb +80 -1
- data/spec/integration/plugin_test.rb +179 -128
- data/spec/integration/prepared_statement_test.rb +92 -91
- data/spec/integration/schema_test.rb +42 -23
- data/spec/integration/spec_helper.rb +25 -31
- data/spec/integration/timezone_test.rb +38 -12
- data/spec/integration/transaction_test.rb +161 -34
- data/spec/integration/type_test.rb +3 -3
- data/spec/model/association_reflection_spec.rb +83 -7
- data/spec/model/associations_spec.rb +393 -676
- data/spec/model/base_spec.rb +186 -116
- data/spec/model/dataset_methods_spec.rb +7 -27
- data/spec/model/eager_loading_spec.rb +343 -867
- data/spec/model/hooks_spec.rb +160 -79
- data/spec/model/model_spec.rb +118 -165
- data/spec/model/plugins_spec.rb +7 -13
- data/spec/model/record_spec.rb +138 -207
- data/spec/model/spec_helper.rb +10 -73
- metadata +14 -8
data/spec/core/spec_helper.rb
CHANGED
@@ -10,93 +10,6 @@ if ENV['SEQUEL_COLUMNS_INTROSPECTION']
|
|
10
10
|
Sequel::Dataset.introspect_all_columns
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
def update(*args)
|
19
|
-
@db.execute update_sql(*args)
|
20
|
-
end
|
21
|
-
|
22
|
-
def fetch_rows(sql)
|
23
|
-
@db.execute(sql)
|
24
|
-
yield({:id => 1, :x => 1})
|
25
|
-
end
|
26
|
-
|
27
|
-
def quoted_identifier(c)
|
28
|
-
"\"#{c}\""
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
class MockDatabase < Sequel::Database
|
33
|
-
set_adapter_scheme :mock
|
34
|
-
@@quote_identifiers = false
|
35
|
-
self.identifier_input_method = nil
|
36
|
-
self.identifier_output_method = nil
|
37
|
-
attr_reader :sqls
|
38
|
-
|
39
|
-
def execute(sql, opts={})
|
40
|
-
@sqls ||= []
|
41
|
-
@sqls << sql
|
42
|
-
end
|
43
|
-
|
44
|
-
def reset
|
45
|
-
@sqls = []
|
46
|
-
end
|
47
|
-
|
48
|
-
def transaction(opts={}); yield; end
|
49
|
-
|
50
|
-
def dataset; MockDataset.new(self); end
|
51
|
-
end
|
52
|
-
|
53
|
-
class SchemaDummyDatabase < Sequel::Database
|
54
|
-
attr_reader :sqls
|
55
|
-
self.identifier_input_method = nil
|
56
|
-
self.identifier_output_method = nil
|
57
|
-
|
58
|
-
def execute(sql, opts={})
|
59
|
-
@sqls ||= []
|
60
|
-
@sqls << sql
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
class DummyDataset < Sequel::Dataset
|
65
|
-
def first
|
66
|
-
raise if @opts[:from] == [:a]
|
67
|
-
true
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
class DummyDatabase < Sequel::Database
|
72
|
-
attr_reader :sqls
|
73
|
-
|
74
|
-
def execute(sql, opts={})
|
75
|
-
@sqls ||= []
|
76
|
-
@sqls << sql
|
77
|
-
end
|
78
|
-
|
79
|
-
def transaction; yield; end
|
80
|
-
|
81
|
-
def dataset
|
82
|
-
DummyDataset.new(self)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
class Dummy2Database < Sequel::Database
|
87
|
-
attr_reader :sql
|
88
|
-
def execute(sql); @sql = sql; end
|
89
|
-
def transaction; yield; end
|
90
|
-
end
|
91
|
-
|
92
|
-
class DummyDataset < Sequel::Dataset
|
93
|
-
VALUES = [
|
94
|
-
{:a => 1, :b => 2},
|
95
|
-
{:a => 3, :b => 4},
|
96
|
-
{:a => 5, :b => 6}
|
97
|
-
]
|
98
|
-
def fetch_rows(sql, &block)
|
99
|
-
VALUES.each(&block)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
13
|
+
Sequel.quote_identifiers = false
|
14
|
+
Sequel.identifier_input_method = nil
|
15
|
+
Sequel.identifier_output_method = nil
|
@@ -8,7 +8,7 @@ describe "class_table_inheritance plugin" do
|
|
8
8
|
:managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer}]],
|
9
9
|
:executives=>[[:id, {:type=>:integer}], [:num_managers, {:type=>:integer}]],
|
10
10
|
:staff=>[[:id, {:type=>:integer}], [:manager_id, {:type=>:integer}]],
|
11
|
-
}[table]
|
11
|
+
}[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
|
12
12
|
end
|
13
13
|
def db.dataset(*args)
|
14
14
|
ds = super(*args)
|
@@ -0,0 +1,199 @@
|
|
1
|
+
require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
2
|
+
|
3
|
+
describe "Sequel::Plugins::DatasetAssociations" do
|
4
|
+
before do
|
5
|
+
@db = Sequel::Database.new
|
6
|
+
@Base = Class.new(Sequel::Model)
|
7
|
+
@Base.plugin :dataset_associations
|
8
|
+
|
9
|
+
@Artist = Class.new(@Base)
|
10
|
+
@Album = Class.new(@Base)
|
11
|
+
@Tag = Class.new(@Base)
|
12
|
+
|
13
|
+
@Artist.meta_def(:name){'Artist'}
|
14
|
+
@Album.meta_def(:name){'Album'}
|
15
|
+
@Tag.meta_def(:name){'Tag'}
|
16
|
+
|
17
|
+
@Artist.dataset = @db[:artists]
|
18
|
+
@Album.dataset = @db[:albums]
|
19
|
+
@Tag.dataset = @db[:tags]
|
20
|
+
|
21
|
+
@Artist.columns :id, :name
|
22
|
+
@Album.columns :id, :name, :artist_id
|
23
|
+
@Tag.columns :id, :name
|
24
|
+
|
25
|
+
@Artist.plugin :many_through_many
|
26
|
+
@Artist.one_to_many :albums, :class=>@Album
|
27
|
+
@Artist.one_to_one :first_album, :class=>@Album
|
28
|
+
@Album.many_to_one :artist, :class=>@Artist
|
29
|
+
@Album.many_to_many :tags, :class=>@Tag
|
30
|
+
@Tag.many_to_many :albums, :class=>@Album
|
31
|
+
@Artist.many_through_many :tags, [[:albums, :artist_id, :id], [:albums_tags, :album_id, :tag_id]], :class=>@Tag
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should work for many_to_one associations" do
|
35
|
+
ds = @Album.artists
|
36
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
37
|
+
ds.model.should == @Artist
|
38
|
+
ds.sql.should == "SELECT * FROM artists WHERE (artists.id IN (SELECT albums.artist_id FROM albums))"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should work for one_to_many associations" do
|
42
|
+
ds = @Artist.albums
|
43
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
44
|
+
ds.model.should == @Album
|
45
|
+
ds.sql.should == "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists))"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should work for one_to_one associations" do
|
49
|
+
ds = @Artist.first_albums
|
50
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
51
|
+
ds.model.should == @Album
|
52
|
+
ds.sql.should == "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists))"
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should work for many_to_many associations" do
|
56
|
+
ds = @Album.tags
|
57
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
58
|
+
ds.model.should == @Tag
|
59
|
+
ds.sql.should == "SELECT tags.* FROM tags WHERE (tags.id IN (SELECT albums_tags.tag_id FROM albums INNER JOIN albums_tags ON (albums_tags.album_id = albums.id)))"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should work for many_through_many associations" do
|
63
|
+
ds = @Artist.tags
|
64
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
65
|
+
ds.model.should == @Tag
|
66
|
+
ds.sql.should == "SELECT tags.* FROM tags WHERE (tags.id IN (SELECT albums_tags.tag_id FROM artists INNER JOIN albums ON (albums.artist_id = artists.id) INNER JOIN albums_tags ON (albums_tags.album_id = albums.id)))"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should have an associated method that takes an association symbol" do
|
70
|
+
ds = @Album.associated(:artist)
|
71
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
72
|
+
ds.model.should == @Artist
|
73
|
+
ds.sql.should == "SELECT * FROM artists WHERE (artists.id IN (SELECT albums.artist_id FROM albums))"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should raise an Error if an invalid association is given to associated" do
|
77
|
+
proc{@Album.associated(:foo)}.should raise_error(Sequel::Error)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should raise an Error if an unrecognized association type is used" do
|
81
|
+
@Album.association_reflection(:artist)[:type] = :foo
|
82
|
+
proc{@Album.artists}.should raise_error(Sequel::Error)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should work correctly when chaining" do
|
86
|
+
ds = @Artist.albums.tags
|
87
|
+
ds.should be_a_kind_of(Sequel::Dataset)
|
88
|
+
ds.model.should == @Tag
|
89
|
+
ds.sql.should == "SELECT tags.* FROM tags WHERE (tags.id IN (SELECT albums_tags.tag_id FROM albums INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE (albums.artist_id IN (SELECT artists.id FROM artists))))"
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should deal correctly with filters before the association method" do
|
93
|
+
@Artist.filter(:id=>1).albums.sql.should == "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists WHERE (id = 1)))"
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should deal correctly with filters after the association method" do
|
97
|
+
@Artist.albums.filter(:id=>1).sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id = 1))"
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should deal correctly with block on the association" do
|
101
|
+
@Artist.one_to_many :albums, :clone=>:albums do |ds| ds.filter(:id=>1..100) end
|
102
|
+
@Artist.albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id >= 1) AND (id <= 100))"
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should deal correctly with :conditions option on the association" do
|
106
|
+
@Artist.one_to_many :albums, :clone=>:albums, :conditions=>{:id=>1..100}
|
107
|
+
@Artist.albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id >= 1) AND (id <= 100))"
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should deal correctly with :distinct option on the association" do
|
111
|
+
@Artist.one_to_many :albums, :clone=>:albums, :distinct=>true
|
112
|
+
@Artist.albums.sql.should == "SELECT DISTINCT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists))"
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should deal correctly with :eager option on the association" do
|
116
|
+
@Artist.one_to_many :albums, :clone=>:albums, :eager=>:tags
|
117
|
+
@Artist.albums.opts[:eager].should == {:tags=>nil}
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should deal correctly with :eager_block option on the association, ignoring the association block" do
|
121
|
+
@Artist.one_to_many :albums, :clone=>:albums, :eager_block=>proc{|ds| ds.filter(:id=>1..100)} do |ds| ds.filter(:id=>2..200) end
|
122
|
+
@Artist.albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id >= 1) AND (id <= 100))"
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should deal correctly with :extend option on the association" do
|
126
|
+
@Artist.one_to_many :albums, :clone=>:albums, :extend=>Module.new{def foo(x) filter(:id=>x) end}
|
127
|
+
@Artist.albums.foo(1).sql.should == "SELECT * FROM albums WHERE ((albums.artist_id IN (SELECT artists.id FROM artists)) AND (id = 1))"
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should deal correctly with :order option on the association" do
|
131
|
+
@Artist.one_to_many :albums, :clone=>:albums, :order=>:name
|
132
|
+
@Artist.albums.sql.should == "SELECT * FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists)) ORDER BY name"
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should deal correctly with :select option on the association" do
|
136
|
+
@Artist.one_to_many :albums, :clone=>:albums, :select=>[:id, :name]
|
137
|
+
@Artist.albums.sql.should == "SELECT id, name FROM albums WHERE (albums.artist_id IN (SELECT artists.id FROM artists))"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "Sequel::Plugins::DatasetAssociations with composite keys" do
|
142
|
+
before do
|
143
|
+
@db = Sequel::Database.new
|
144
|
+
@Base = Class.new(Sequel::Model)
|
145
|
+
@Base.plugin :dataset_associations
|
146
|
+
|
147
|
+
@Artist = Class.new(@Base)
|
148
|
+
@Album = Class.new(@Base)
|
149
|
+
@Tag = Class.new(@Base)
|
150
|
+
|
151
|
+
@Artist.meta_def(:name){'Artist'}
|
152
|
+
@Album.meta_def(:name){'Album'}
|
153
|
+
@Tag.meta_def(:name){'Tag'}
|
154
|
+
|
155
|
+
@Artist.dataset = @db[:artists]
|
156
|
+
@Album.dataset = @db[:albums]
|
157
|
+
@Tag.dataset = @db[:tags]
|
158
|
+
|
159
|
+
@Artist.set_primary_key([:id1, :id2])
|
160
|
+
@Album.set_primary_key([:id1, :id2])
|
161
|
+
@Tag.set_primary_key([:id1, :id2])
|
162
|
+
|
163
|
+
@Artist.columns :id1, :id2, :name
|
164
|
+
@Album.columns :id1, :id2, :name, :artist_id1, :artist_id2
|
165
|
+
@Tag.columns :id1, :id2, :name
|
166
|
+
|
167
|
+
@Artist.plugin :many_through_many
|
168
|
+
@Artist.one_to_many :albums, :class=>@Album, :key=>[:artist_id1, :artist_id2]
|
169
|
+
@Artist.one_to_one :first_album, :class=>@Album, :key=>[:artist_id1, :artist_id2]
|
170
|
+
@Album.many_to_one :artist, :class=>@Artist, :key=>[:artist_id1, :artist_id2]
|
171
|
+
@Album.many_to_many :tags, :class=>@Tag, :left_key=>[:album_id1, :album_id2], :right_key=>[:tag_id1, :tag_id2]
|
172
|
+
@Tag.many_to_many :albums, :class=>@Album, :right_key=>[:album_id1, :album_id2], :left_key=>[:tag_id1, :tag_id2]
|
173
|
+
@Artist.many_through_many :tags, [[:albums, [:artist_id1, :artist_id2], [:id1, :id2]], [:albums_tags, [:album_id1, :album_id2], [:tag_id1, :tag_id2]]], :class=>@Tag
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should work for many_to_one associations" do
|
177
|
+
@Album.artists.sql.should == "SELECT * FROM artists WHERE ((artists.id1, artists.id2) IN (SELECT albums.artist_id1, albums.artist_id2 FROM albums))"
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should work for one_to_many associations" do
|
181
|
+
@Artist.albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists))"
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should work for one_to_one associations" do
|
185
|
+
@Artist.first_albums.sql.should == "SELECT * FROM albums WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists))"
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should work for many_to_many associations" do
|
189
|
+
@Album.tags.sql.should == "SELECT tags.* FROM tags WHERE ((tags.id1, tags.id2) IN (SELECT albums_tags.tag_id1, albums_tags.tag_id2 FROM albums INNER JOIN albums_tags ON ((albums_tags.album_id1 = albums.id1) AND (albums_tags.album_id2 = albums.id2))))"
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should work for many_through_many associations" do
|
193
|
+
@Artist.tags.sql.should == "SELECT tags.* FROM tags WHERE ((tags.id1, tags.id2) IN (SELECT albums_tags.tag_id1, albums_tags.tag_id2 FROM artists INNER JOIN albums ON ((albums.artist_id1 = artists.id1) AND (albums.artist_id2 = artists.id2)) INNER JOIN albums_tags ON ((albums_tags.album_id1 = albums.id1) AND (albums_tags.album_id2 = albums.id2))))"
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should work correctly when chaining" do
|
197
|
+
@Artist.albums.tags.sql.should == "SELECT tags.* FROM tags WHERE ((tags.id1, tags.id2) IN (SELECT albums_tags.tag_id1, albums_tags.tag_id2 FROM albums INNER JOIN albums_tags ON ((albums_tags.album_id1 = albums.id1) AND (albums_tags.album_id2 = albums.id2)) WHERE ((albums.artist_id1, albums.artist_id2) IN (SELECT artists.id1, artists.id2 FROM artists))))"
|
198
|
+
end
|
199
|
+
end
|
@@ -177,3 +177,74 @@ describe "InstanceHooks plugin" do
|
|
177
177
|
@r.should == [2, 1, 4, 3]
|
178
178
|
end
|
179
179
|
end
|
180
|
+
|
181
|
+
describe "InstanceHooks plugin with transactions" do
|
182
|
+
before do
|
183
|
+
@logger = Object.new
|
184
|
+
def @logger.method_missing(meth, sql)
|
185
|
+
(@sqls ||= []) << sql
|
186
|
+
end
|
187
|
+
def @logger.sqls
|
188
|
+
@sqls
|
189
|
+
end
|
190
|
+
@db = Class.new(Sequel::Database) do
|
191
|
+
def connect(*)
|
192
|
+
Object.new
|
193
|
+
end
|
194
|
+
def log_connection_execute(conn, sql)
|
195
|
+
execute(sql)
|
196
|
+
end
|
197
|
+
def execute(sql, opts={})
|
198
|
+
@loggers.each{|l| l.info(sql)}
|
199
|
+
end
|
200
|
+
end.new(:loggers=>[@logger])
|
201
|
+
pr = proc{|x| r(x)}
|
202
|
+
@c = Class.new(Sequel::Model(@db[:items])) do
|
203
|
+
attr_accessor :rb
|
204
|
+
def _delete
|
205
|
+
end
|
206
|
+
def after_save
|
207
|
+
db.execute('as')
|
208
|
+
raise Sequel::Rollback if rb
|
209
|
+
end
|
210
|
+
def after_destroy
|
211
|
+
db.execute('ad')
|
212
|
+
raise Sequel::Rollback if rb
|
213
|
+
end
|
214
|
+
end
|
215
|
+
@c.use_transactions = true
|
216
|
+
@c.plugin :instance_hooks
|
217
|
+
@o = @c.load({:id=>1})
|
218
|
+
@or = @c.load({:id=>1})
|
219
|
+
@or.rb = true
|
220
|
+
@r = []
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should support after_commit_hook" do
|
224
|
+
@o.after_commit_hook{@db.execute('ac1')}
|
225
|
+
@o.after_commit_hook{@db.execute('ac2')}
|
226
|
+
@o.save.should_not be_nil
|
227
|
+
@logger.sqls.should == ['BEGIN', 'as', 'COMMIT', 'ac1', 'ac2']
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should support after_rollback_hook" do
|
231
|
+
@or.after_rollback_hook{@db.execute('ar1')}
|
232
|
+
@or.after_rollback_hook{@db.execute('ar2')}
|
233
|
+
@or.save.should be_nil
|
234
|
+
@logger.sqls.should == ['BEGIN', 'as', 'ROLLBACK', 'ar1', 'ar2']
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should support after_commit_hook" do
|
238
|
+
@o.after_destroy_commit_hook{@db.execute('adc1')}
|
239
|
+
@o.after_destroy_commit_hook{@db.execute('adc2')}
|
240
|
+
@o.destroy.should_not be_nil
|
241
|
+
@logger.sqls.should == ['BEGIN', 'ad', 'COMMIT', 'adc1', 'adc2']
|
242
|
+
end
|
243
|
+
|
244
|
+
it "should support after_rollback_hook" do
|
245
|
+
@or.after_destroy_rollback_hook{@db.execute('adr1')}
|
246
|
+
@or.after_destroy_rollback_hook{@db.execute('adr2')}
|
247
|
+
@or.destroy.should be_nil
|
248
|
+
@logger.sqls.should == ['BEGIN', 'ad', 'ROLLBACK', 'adr1', 'adr2']
|
249
|
+
end
|
250
|
+
end
|
@@ -66,8 +66,28 @@ describe "Sequel named_timezones extension" do
|
|
66
66
|
end
|
67
67
|
|
68
68
|
it "should work with the thread_local_timezones extension" do
|
69
|
-
|
70
|
-
|
69
|
+
q, q1, q2 = Queue.new, Queue.new, Queue.new
|
70
|
+
tz1, tz2 = nil, nil
|
71
|
+
t1 = Thread.new do
|
72
|
+
Sequel.thread_application_timezone = 'America/New_York'
|
73
|
+
q2.push nil
|
74
|
+
q.pop
|
75
|
+
tz1 = Sequel.application_timezone
|
76
|
+
end
|
77
|
+
t2 = Thread.new do
|
78
|
+
Sequel.thread_application_timezone = 'America/Los_Angeles'
|
79
|
+
q2.push nil
|
80
|
+
q1.pop
|
81
|
+
tz2 = Sequel.application_timezone
|
82
|
+
end
|
83
|
+
q2.pop
|
84
|
+
q2.pop
|
85
|
+
q.push nil
|
86
|
+
q1.push nil
|
87
|
+
t1.join
|
88
|
+
t2.join
|
89
|
+
tz1.should == @tz_out
|
90
|
+
tz2.should == @tz_in
|
71
91
|
end
|
72
92
|
end
|
73
93
|
end
|
@@ -57,7 +57,7 @@ describe Sequel::Model, "create_table and schema" do
|
|
57
57
|
|
58
58
|
it "should reload the schema from the database" do
|
59
59
|
schem = {:name=>{:type=>:string}, :price=>{:type=>:float}}
|
60
|
-
@model.db.should_receive(:schema).with(
|
60
|
+
@model.db.should_receive(:schema).with(@model.dataset, :reload=>true).and_return(schem.to_a.sort_by{|x| x[0].to_s})
|
61
61
|
@model.create_table
|
62
62
|
@model.db_schema.should == schem
|
63
63
|
@model.instance_variable_get(:@columns).should == [:name, :price]
|
@@ -22,11 +22,11 @@ describe "Serialization plugin" do
|
|
22
22
|
it "should allow setting additional serializable attributes via plugin :serialization call" do
|
23
23
|
@c.plugin :serialization, :yaml, :abc
|
24
24
|
@c.create(:abc => 1, :def=> 2)
|
25
|
-
MODEL_DB.sqls.last.should =~ /INSERT INTO items \((abc, def|def, abc)\) VALUES \(('--- 1\n', 2|2, '--- 1\n')\)/
|
25
|
+
MODEL_DB.sqls.last.should =~ /INSERT INTO items \((abc, def|def, abc)\) VALUES \(('--- 1\n(\.\.\.\n)?', 2|2, '--- 1\n(\.\.\.\n)?')\)/
|
26
26
|
|
27
27
|
@c.plugin :serialization, :marshal, :def
|
28
28
|
@c.create(:abc => 1, :def=> 1)
|
29
|
-
MODEL_DB.sqls.last.should =~ /INSERT INTO items \((abc, def|def, abc)\) VALUES \(('--- 1\n', 'BAhpBg==\n'|'BAhpBg==\n', '--- 1\n')\)/
|
29
|
+
MODEL_DB.sqls.last.should =~ /INSERT INTO items \((abc, def|def, abc)\) VALUES \(('--- 1\n(\.\.\.\n)?', 'BAhpBg==\n'|'BAhpBg==\n', '--- 1\n(\.\.\.\n)?')\)/
|
30
30
|
|
31
31
|
@c.plugin :serialization, :json, :ghi
|
32
32
|
@c.create(:ghi => [123])
|
@@ -38,10 +38,7 @@ describe "Serialization plugin" do
|
|
38
38
|
@c.create(:abc => 1)
|
39
39
|
@c.create(:abc => "hello")
|
40
40
|
|
41
|
-
MODEL_DB.sqls.should == [ \
|
42
|
-
"INSERT INTO items (abc) VALUES ('--- 1\n')", \
|
43
|
-
"INSERT INTO items (abc) VALUES ('--- hello\n')", \
|
44
|
-
]
|
41
|
+
MODEL_DB.sqls.map{|s| s.sub("...\n", '')}.should == ["INSERT INTO items (abc) VALUES ('--- 1\n')", "INSERT INTO items (abc) VALUES ('--- hello\n')"]
|
45
42
|
end
|
46
43
|
|
47
44
|
it "serialization_format should be the serialization format used" do
|
@@ -97,7 +94,7 @@ describe "Serialization plugin" do
|
|
97
94
|
|
98
95
|
o.update(:abc => 23)
|
99
96
|
@c.create(:abc => [1, 2, 3])
|
100
|
-
MODEL_DB.sqls.should == ["UPDATE items SET abc = '
|
97
|
+
MODEL_DB.sqls.should == ["UPDATE items SET abc = '#{23.to_yaml}' WHERE (id = 1)",
|
101
98
|
"INSERT INTO items (abc) VALUES ('#{[1, 2, 3].to_yaml}')"]
|
102
99
|
end
|
103
100
|
|
@@ -164,7 +161,7 @@ describe "Serialization plugin" do
|
|
164
161
|
|
165
162
|
o.update(:abc => 23)
|
166
163
|
Class.new(@c).create(:abc => [1, 2, 3])
|
167
|
-
MODEL_DB.sqls.should == ["UPDATE items SET abc = '
|
164
|
+
MODEL_DB.sqls.should == ["UPDATE items SET abc = '#{23.to_yaml}' WHERE (id = 1)",
|
168
165
|
"INSERT INTO items (abc) VALUES ('#{[1, 2, 3].to_yaml}')"]
|
169
166
|
end
|
170
167
|
|