sequel 4.42.1 → 4.43.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +35 -1
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/doc/release_notes/4.43.0.txt +87 -0
- data/doc/sql.rdoc +26 -27
- data/doc/testing.rdoc +2 -0
- data/doc/validations.rdoc +1 -1
- data/lib/sequel/adapters/ado.rb +5 -0
- data/lib/sequel/adapters/cubrid.rb +5 -0
- data/lib/sequel/adapters/ibmdb.rb +5 -0
- data/lib/sequel/adapters/jdbc.rb +6 -0
- data/lib/sequel/adapters/jdbc/derby.rb +5 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +9 -5
- data/lib/sequel/adapters/jdbc/postgresql.rb +1 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +5 -0
- data/lib/sequel/adapters/jdbc/transactions.rb +5 -0
- data/lib/sequel/adapters/mock.rb +12 -9
- data/lib/sequel/adapters/mysql.rb +6 -0
- data/lib/sequel/adapters/mysql2.rb +7 -2
- data/lib/sequel/adapters/oracle.rb +5 -0
- data/lib/sequel/adapters/shared/db2.rb +7 -1
- data/lib/sequel/adapters/shared/mssql.rb +5 -0
- data/lib/sequel/adapters/shared/mysql.rb +8 -1
- data/lib/sequel/adapters/shared/oracle.rb +20 -12
- data/lib/sequel/adapters/shared/postgres.rb +11 -2
- data/lib/sequel/adapters/shared/sqlanywhere.rb +6 -0
- data/lib/sequel/adapters/shared/sqlite.rb +29 -0
- data/lib/sequel/adapters/sqlanywhere.rb +5 -0
- data/lib/sequel/adapters/sqlite.rb +13 -0
- data/lib/sequel/connection_pool/sharded_single.rb +5 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +5 -0
- data/lib/sequel/connection_pool/single.rb +15 -6
- data/lib/sequel/database/dataset.rb +3 -0
- data/lib/sequel/database/misc.rb +22 -1
- data/lib/sequel/database/query.rb +2 -4
- data/lib/sequel/dataset/actions.rb +0 -1
- data/lib/sequel/dataset/misc.rb +2 -4
- data/lib/sequel/dataset/query.rb +23 -6
- data/lib/sequel/extensions/_model_constraint_validations.rb +16 -0
- data/lib/sequel/extensions/_model_pg_row.rb +47 -0
- data/lib/sequel/extensions/looser_typecasting.rb +2 -0
- data/lib/sequel/extensions/migration.rb +12 -1
- data/lib/sequel/extensions/pg_array.rb +6 -0
- data/lib/sequel/extensions/pg_enum.rb +2 -1
- data/lib/sequel/extensions/pg_range.rb +6 -0
- data/lib/sequel/extensions/pg_row.rb +8 -0
- data/lib/sequel/model/associations.rb +3 -1
- data/lib/sequel/model/base.rb +14 -3
- data/lib/sequel/plugins/constraint_validations.rb +1 -8
- data/lib/sequel/plugins/instance_filters.rb +1 -1
- data/lib/sequel/plugins/pg_row.rb +1 -40
- data/lib/sequel/plugins/prepared_statements.rb +51 -20
- data/lib/sequel/plugins/prepared_statements_associations.rb +22 -4
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +9 -1
- data/lib/sequel/plugins/sharding.rb +5 -0
- data/lib/sequel/plugins/update_primary_key.rb +1 -1
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/spec_helper.rb +4 -0
- data/spec/core/connection_pool_spec.rb +10 -0
- data/spec/core/database_spec.rb +29 -0
- data/spec/extensions/blacklist_security_spec.rb +4 -4
- data/spec/extensions/defaults_setter_spec.rb +1 -1
- data/spec/extensions/force_encoding_spec.rb +3 -2
- data/spec/extensions/identifier_mangling_spec.rb +7 -0
- data/spec/extensions/instance_filters_spec.rb +1 -0
- data/spec/extensions/migration_spec.rb +19 -0
- data/spec/extensions/pg_array_spec.rb +5 -0
- data/spec/extensions/pg_range_spec.rb +5 -0
- data/spec/extensions/pg_row_spec.rb +9 -0
- data/spec/extensions/prepared_statements_associations_spec.rb +45 -1
- data/spec/extensions/prepared_statements_spec.rb +138 -41
- data/spec/extensions/prepared_statements_with_pk_spec.rb +7 -0
- data/spec/extensions/serialization_spec.rb +6 -6
- data/spec/extensions/single_table_inheritance_spec.rb +3 -3
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/integration/associations_test.rb +2 -2
- data/spec/integration/dataset_test.rb +0 -4
- data/spec/integration/eager_loader_test.rb +5 -5
- data/spec/integration/plugin_test.rb +8 -6
- data/spec/integration/schema_test.rb +2 -2
- data/spec/integration/spec_helper.rb +10 -0
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +5 -5
- data/spec/model/associations_spec.rb +13 -6
- data/spec/model/base_spec.rb +1 -1
- data/spec/model/hooks_spec.rb +4 -4
- data/spec/model/model_spec.rb +2 -2
- data/spec/model/record_spec.rb +17 -18
- metadata +6 -2
@@ -14,6 +14,13 @@ describe "identifier_mangling extension" do
|
|
14
14
|
db.quote_identifiers?.must_equal true
|
15
15
|
end
|
16
16
|
|
17
|
+
it "should respect the :quote_identifiers setting" do
|
18
|
+
db = Sequel::Database.new(:identifier_mangling=>true)
|
19
|
+
db.quote_identifiers?.must_equal false
|
20
|
+
db.quote_identifiers = true
|
21
|
+
db.quote_identifiers?.must_equal true
|
22
|
+
end
|
23
|
+
|
17
24
|
it "should upcase on input and downcase on output by default" do
|
18
25
|
db = Sequel::Database.new(:identifier_mangling=>true)
|
19
26
|
db.send(:identifier_input_method_default).must_equal :upcase
|
@@ -39,6 +39,7 @@ describe "instance_filters plugin" do
|
|
39
39
|
|
40
40
|
@p = @c.load(:id=>1, :name=>'John', :num=>1)
|
41
41
|
@p.instance_variable_set(:@this, @p.this.with_numrows(1))
|
42
|
+
@c.instance_variable_set(:@fast_instance_delete_sql, nil)
|
42
43
|
@p.destroy
|
43
44
|
DB.sqls.must_equal ["DELETE FROM people WHERE (id = 1)"]
|
44
45
|
@p.instance_filter(:name=>'Jim')
|
@@ -772,4 +772,23 @@ describe "Sequel::TimestampMigrator" do
|
|
772
772
|
Sequel::TimestampMigrator.run(@db, "spec/files/transaction_unspecified_migrations", :use_transactions=>false)
|
773
773
|
@db.sqls.must_equal ["SELECT NULL AS nil FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)", "SELECT NULL AS nil FROM schema_info LIMIT 1", "SELECT filename FROM schema_migrations ORDER BY filename", "CREATE TABLE sm11111 (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('001_create_alt_basic.rb')", "CREATE TABLE sm (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('002_create_basic.rb')"]
|
774
774
|
end
|
775
|
+
|
776
|
+
it "should use shorter primary key field on MySQL if creating schema migrations table fails" do
|
777
|
+
def @db.database_type; :mysql end
|
778
|
+
def @db.execute_ddl(sql, *)
|
779
|
+
super
|
780
|
+
raise Sequel::DatabaseError, "Specified key was too long; max key length is 767 bytes" if sql =~ /varchar\(255\)/
|
781
|
+
end
|
782
|
+
Sequel::TimestampMigrator.run(@db, "spec/files/transaction_unspecified_migrations", :use_transactions=>false)
|
783
|
+
@db.sqls.must_equal ["SELECT NULL AS nil FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)", "CREATE TABLE schema_migrations (filename varchar(190) PRIMARY KEY)", "SELECT NULL AS nil FROM schema_info LIMIT 1", "SELECT filename FROM schema_migrations ORDER BY filename", "CREATE TABLE sm11111 (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('001_create_alt_basic.rb')", "CREATE TABLE sm (smc1 integer)", "INSERT INTO schema_migrations (filename) VALUES ('002_create_basic.rb')"]
|
784
|
+
end
|
785
|
+
|
786
|
+
it "should not use shorter primary key field on other databases if creating schema migrations table fails" do
|
787
|
+
def @db.execute_ddl(sql, *)
|
788
|
+
super
|
789
|
+
raise Sequel::DatabaseError, "Specified key was too long; max key length is 767 bytes" if sql =~ /varchar\(255\)/
|
790
|
+
end
|
791
|
+
proc{Sequel::TimestampMigrator.run(@db, "spec/files/transaction_unspecified_migrations", :use_transactions=>false)}.must_raise Sequel::DatabaseError
|
792
|
+
@db.sqls.must_equal ["SELECT NULL AS nil FROM schema_migrations LIMIT 1", "CREATE TABLE schema_migrations (filename varchar(255) PRIMARY KEY)"]
|
793
|
+
end
|
775
794
|
end
|
@@ -330,6 +330,11 @@ describe "pg_array extension" do
|
|
330
330
|
@db.literal(Sequel::Postgres::PG_TYPES[3].call('{}')).must_equal "'{}'::blah[]"
|
331
331
|
end
|
332
332
|
|
333
|
+
it "should not support registering custom array types on a per-Database basis for frozen databases" do
|
334
|
+
@db.freeze
|
335
|
+
proc{@db.register_array_type('banana', :oid=>7865){|s| s}}.must_raise RuntimeError, TypeError
|
336
|
+
end
|
337
|
+
|
333
338
|
it "should support registering custom array types on a per-Database basis" do
|
334
339
|
@db.register_array_type('banana', :oid=>7865){|s| s}
|
335
340
|
@db.typecast_value(:banana_array, []).class.must_equal(Sequel::Postgres::PGArray)
|
@@ -170,6 +170,11 @@ describe "pg_range extension" do
|
|
170
170
|
Sequel::Postgres::PG_TYPES[331].call('[1,3)').must_be_kind_of(@R)
|
171
171
|
end
|
172
172
|
|
173
|
+
it "should not support registering custom range types on a per-Database basis for frozen databases" do
|
174
|
+
@db.freeze
|
175
|
+
proc{@db.register_range_type('banana', :oid=>7865){|s| s}}.must_raise RuntimeError, TypeError
|
176
|
+
end
|
177
|
+
|
173
178
|
it "should support registering custom range types on a per-Database basis" do
|
174
179
|
@db.register_range_type('banana', :oid=>7865){|s| s}
|
175
180
|
@db.typecast_value(:banana, '[1,2]').class.must_equal(Sequel::Postgres::PGRange)
|
@@ -231,6 +231,15 @@ describe "pg_row extension" do
|
|
231
231
|
@db.literal(p1.call('(1,b)')).must_equal "ROW(1, 'bb')::foo.bar"
|
232
232
|
end
|
233
233
|
|
234
|
+
it "should not allow registering on a frozen database" do
|
235
|
+
@db.conversion_procs[4] = proc{|s| s.to_i}
|
236
|
+
@db.conversion_procs[5] = proc{|s| s * 2}
|
237
|
+
@db.fetch = [[], [{:oid=>1, :typrelid=>2, :typarray=>3}], [{:attname=>'bar', :atttypid=>4}, {:attname=>'baz', :atttypid=>5}]]
|
238
|
+
c = proc{|h| [h]}
|
239
|
+
@db.freeze
|
240
|
+
proc{@db.register_row_type(:foo, :converter=>c)}.must_raise RuntimeError, TypeError
|
241
|
+
end
|
242
|
+
|
234
243
|
it "should allow registering with a custom converter" do
|
235
244
|
@db.conversion_procs[4] = proc{|s| s.to_i}
|
236
245
|
@db.conversion_procs[5] = proc{|s| s * 2}
|
@@ -2,7 +2,7 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
|
|
2
2
|
|
3
3
|
describe "Sequel::Plugins::PreparedStatementsAssociations" do
|
4
4
|
before do
|
5
|
-
@db = Sequel.mock
|
5
|
+
@db = Sequel.mock(:servers=>{:foo=>{}})
|
6
6
|
@db.extend_datasets do
|
7
7
|
def select_sql
|
8
8
|
sql = super
|
@@ -52,6 +52,43 @@ describe "Sequel::Plugins::PreparedStatementsAssociations" do
|
|
52
52
|
@db.sqls.must_equal ["SELECT tags.id, tags.id2 FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) WHERE (albums.artist_id = 1) LIMIT 1 -- prepared"]
|
53
53
|
end
|
54
54
|
|
55
|
+
it "should run correct shard for associations when also using sharding plugin" do
|
56
|
+
@Artist.plugin :sharding
|
57
|
+
@Album.plugin :sharding
|
58
|
+
|
59
|
+
@Artist.load(:id=>1).set_server(:foo).albums
|
60
|
+
@db.sqls.must_equal ["SELECT id, artist_id, id2, artist_id2 FROM albums WHERE (albums.artist_id = 1) -- prepared -- foo"]
|
61
|
+
|
62
|
+
@Artist.load(:id=>1).set_server(:foo).album
|
63
|
+
@db.sqls.must_equal ["SELECT id, artist_id, id2, artist_id2 FROM albums WHERE (albums.artist_id = 1) LIMIT 1 -- prepared -- foo"]
|
64
|
+
|
65
|
+
@Album.load(:id=>1, :artist_id=>2).set_server(:foo).artist
|
66
|
+
@db.sqls.must_equal ["SELECT id, id2 FROM artists WHERE (artists.id = 2) LIMIT 1 -- prepared -- foo"]
|
67
|
+
|
68
|
+
@Album.load(:id=>1, :artist_id=>2).set_server(:foo).tags
|
69
|
+
@db.sqls.must_equal ["SELECT tags.id, tags.id2 FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE (albums_tags.album_id = 1) -- prepared -- foo"]
|
70
|
+
|
71
|
+
@Album.load(:id=>1, :artist_id=>2).set_server(:foo).tag
|
72
|
+
@db.sqls.must_equal ["SELECT tags.id, tags.id2 FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) WHERE (albums_tags.album_id = 1) LIMIT 1 -- prepared -- foo"]
|
73
|
+
|
74
|
+
@Artist.load(:id=>1).set_server(:foo).tags
|
75
|
+
@db.sqls.must_equal ["SELECT tags.id, tags.id2 FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) WHERE (albums.artist_id = 1) -- prepared -- foo"]
|
76
|
+
|
77
|
+
@Artist.load(:id=>1).set_server(:foo).tag
|
78
|
+
@db.sqls.must_equal ["SELECT tags.id, tags.id2 FROM tags INNER JOIN albums_tags ON (albums_tags.tag_id = tags.id) INNER JOIN albums ON (albums.id = albums_tags.album_id) WHERE (albums.artist_id = 1) LIMIT 1 -- prepared -- foo"]
|
79
|
+
|
80
|
+
@Tag.plugin :sharding
|
81
|
+
@Tag.plugin :prepared_statements_associations
|
82
|
+
@Tag.many_to_many :albums, :class=>@Album, :join_table=>:albums_tags, :left_key=>:tag_id
|
83
|
+
@Tag.load(:id=>1).set_server(:foo).albums
|
84
|
+
@db.sqls.must_equal ["SELECT albums.id, albums.artist_id, albums.id2, albums.artist_id2 FROM albums INNER JOIN albums_tags ON (albums_tags.album_id = albums.id) WHERE (albums_tags.tag_id = 1) -- prepared -- foo"]
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should not override the shard for associations if not using the sharding plugin" do
|
88
|
+
@Artist.load(:id=>1).set_server(:foo).albums
|
89
|
+
@db.sqls.must_equal ["SELECT id, artist_id, id2, artist_id2 FROM albums WHERE (albums.artist_id = 1) -- prepared"]
|
90
|
+
end
|
91
|
+
|
55
92
|
it "should run correct SQL for composite key associations" do
|
56
93
|
@Artist.one_to_many :albums, :class=>@Album, :key=>[:artist_id, :artist_id2], :primary_key=>[:id, :id2]
|
57
94
|
@Artist.one_to_one :album, :class=>@Album, :key=>[:artist_id, :artist_id2], :primary_key=>[:id, :id2]
|
@@ -156,4 +193,11 @@ describe "Sequel::Plugins::PreparedStatementsAssociations" do
|
|
156
193
|
@Artist.load(:id=>1).oalbums
|
157
194
|
@db.sqls.must_equal ["SELECT * FROM albums WHERE (albums.artist_id = 1)"]
|
158
195
|
end
|
196
|
+
|
197
|
+
it "should work correctly when using an instance specific association" do
|
198
|
+
tag = @Tag
|
199
|
+
@Artist.many_to_one :tag, :key=>nil, :read_only=>true, :dataset=>proc{tag.where(:id=>id).limit(1)}, :reciprocal=>nil, :reciprocal_type=>nil
|
200
|
+
@Artist.load(:id=>1).tag.must_be_nil
|
201
|
+
@db.sqls.must_equal ["SELECT * FROM tags WHERE (id = 1) LIMIT 1"]
|
202
|
+
end
|
159
203
|
end
|
@@ -5,6 +5,7 @@ describe "prepared_statements plugin" do
|
|
5
5
|
@db = Sequel.mock(:fetch=>{:id=>1, :name=>'foo', :i=>2}, :autoid=>proc{|sql| 1}, :numrows=>1, :servers=>{:read_only=>{}})
|
6
6
|
@c = Class.new(Sequel::Model(@db[:people]))
|
7
7
|
@c.columns :id, :name, :i
|
8
|
+
@c.set_primary_key :id
|
8
9
|
@columns = "id, name, i"
|
9
10
|
@c.plugin :prepared_statements
|
10
11
|
@p = @c.load(:id=>1, :name=>'foo', :i=>2)
|
@@ -12,11 +13,6 @@ describe "prepared_statements plugin" do
|
|
12
13
|
@db.sqls
|
13
14
|
end
|
14
15
|
|
15
|
-
it "should correctly lookup by primary key" do
|
16
|
-
@c[1].must_equal @p
|
17
|
-
@db.sqls.must_equal ["SELECT id, name, i FROM people WHERE (id = 1) LIMIT 1 -- read_only"]
|
18
|
-
end
|
19
|
-
|
20
16
|
it "should correctly lookup by primary key for joined dataset" do
|
21
17
|
@c.dataset = @c.dataset.from(:people, :people2)
|
22
18
|
@db.sqls
|
@@ -24,22 +20,46 @@ describe "prepared_statements plugin" do
|
|
24
20
|
@db.sqls.must_equal ["SELECT * FROM people, people2 WHERE (people.id = 1) LIMIT 1 -- read_only"]
|
25
21
|
end
|
26
22
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
23
|
+
it "should use prepared statements for pk lookups only if default is not optimized" do
|
24
|
+
@c.send(:use_prepared_statements_for_pk_lookup?).must_equal false
|
25
|
+
@c.set_primary_key [:id, :name]
|
26
|
+
@c.send(:use_prepared_statements_for_pk_lookup?).must_equal true
|
27
|
+
@c.set_primary_key :id
|
28
|
+
@c.dataset = @c.dataset.from(:people, :people2)
|
29
|
+
@c.send(:use_prepared_statements_for_pk_lookup?).must_equal false
|
30
|
+
@c.dataset = @db[:people].select(:id, :name, :i)
|
31
|
+
@c.send(:use_prepared_statements_for_pk_lookup?).must_equal true
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should use prepared statements for refreshes if default is not optimized" do
|
35
|
+
@p.send(:use_prepared_statements_for?, :refresh).must_equal false
|
36
|
+
@c.set_primary_key [:id, :name]
|
37
|
+
@p.send(:use_prepared_statements_for?, :refresh).must_equal true
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should use prepared statements for deletes if default is not optimized" do
|
41
|
+
@p.send(:use_prepared_statements_for?, :delete).must_equal false
|
42
|
+
@c.set_primary_key [:id, :name]
|
43
|
+
@p.send(:use_prepared_statements_for?, :delete).must_equal true
|
44
|
+
end
|
32
45
|
|
46
|
+
it "should use prepared statements for deletes if default on Oracle and DB2" do
|
47
|
+
def @db.database_type; :oracle end
|
48
|
+
@p.send(:use_prepared_statements_for?, :delete).must_equal true
|
49
|
+
def @db.database_type; :db2 end
|
50
|
+
@p.send(:use_prepared_statements_for?, :delete).must_equal true
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should raise Error for unsupported prepared statement types" do
|
54
|
+
proc{@p.send(:use_prepared_statements_for?, :foo)}.must_raise Sequel::Error
|
55
|
+
end
|
56
|
+
|
57
|
+
prepared_statements_spec = shared_description do
|
33
58
|
it "should correctly update instance" do
|
34
59
|
@p.update(:name=>'bar').must_equal @c.load(:id=>1, :name=>'bar', :i => 2)
|
35
60
|
@db.sqls.must_equal ["UPDATE people SET name = 'bar' WHERE (id = 1)"]
|
36
61
|
end
|
37
62
|
|
38
|
-
it "should correctly create instance" do
|
39
|
-
@c.create(:name=>'foo').must_equal @c.load(:id=>1, :name=>'foo', :i => 2)
|
40
|
-
@db.sqls.must_equal ["INSERT INTO people (name) VALUES ('foo')", "SELECT #{@columns} FROM people WHERE (id = 1) LIMIT 1"]
|
41
|
-
end
|
42
|
-
|
43
63
|
it "should correctly create instance if dataset supports insert_select" do
|
44
64
|
@c.dataset_module do
|
45
65
|
def supports_insert_select?
|
@@ -61,51 +81,128 @@ describe "prepared_statements plugin" do
|
|
61
81
|
end
|
62
82
|
end
|
63
83
|
|
64
|
-
describe "when #use_prepared_statements_for? returns
|
84
|
+
describe "when #use_prepared_statements_for? returns true" do
|
65
85
|
before do
|
66
|
-
@
|
67
|
-
|
86
|
+
@c.class_eval do
|
87
|
+
def self.use_prepared_statements_for_pk_lookup?; true end
|
88
|
+
def use_prepared_statements_for?(type) true end
|
89
|
+
end
|
68
90
|
end
|
69
91
|
|
70
92
|
include prepared_statements_spec
|
71
|
-
end
|
72
93
|
|
73
|
-
|
94
|
+
it "should correctly create instance" do
|
95
|
+
@c.create(:name=>'foo').must_equal @c.load(:id=>1, :name=>'foo', :i => 2)
|
96
|
+
@db.sqls.must_equal ["INSERT INTO people (name) VALUES ('foo')", "SELECT #{@columns} FROM people WHERE (id = 1) LIMIT 1"]
|
97
|
+
end
|
74
98
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
end
|
99
|
+
it "should correctly lookup by primary key" do
|
100
|
+
@c[1].must_equal @p
|
101
|
+
@db.sqls.must_equal ["SELECT id, name, i FROM people WHERE (id = 1) LIMIT 1 -- read_only"]
|
102
|
+
end
|
80
103
|
|
81
|
-
|
82
|
-
|
83
|
-
@
|
104
|
+
it "should correctly delete instance" do
|
105
|
+
@p.destroy.must_equal @p
|
106
|
+
@db.sqls.must_equal ["DELETE FROM people WHERE (id = 1)"]
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should correctly delete instance when specifying server" do
|
110
|
+
@p.set_server(:read_only).destroy.must_equal @p
|
111
|
+
@db.sqls.must_equal ["DELETE FROM people WHERE (id = 1) -- read_only"]
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should correctly update instance when specifying server" do
|
115
|
+
@p.set_server(:read_only).update(:name=>'bar').must_equal @c.load(:id=>1, :name=>'bar', :i => 2)
|
116
|
+
@db.sqls.must_equal ["UPDATE people SET name = 'bar' WHERE (id = 1) -- read_only"]
|
84
117
|
end
|
85
118
|
|
86
|
-
it "should correctly
|
119
|
+
it "should correctly create instance when specifying server" do
|
120
|
+
@c.new(:name=>'foo').set_server(:read_only).save.must_equal @c.load(:id=>1, :name=>'foo', :i => 2)
|
121
|
+
@db.sqls.must_equal ["INSERT INTO people (name) VALUES ('foo') -- read_only", "SELECT #{@columns} FROM people WHERE (id = 1) LIMIT 1 -- read_only"]
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should correctly create instance if dataset supports insert_select when specifying server" do
|
125
|
+
@c.dataset_module do
|
126
|
+
def supports_insert_select?
|
127
|
+
true
|
128
|
+
end
|
129
|
+
def supports_returning?(type)
|
130
|
+
true
|
131
|
+
end
|
132
|
+
def insert_select(h)
|
133
|
+
cache_set(:_fetch, :id=>1, :name=>'foo', :i => 2)
|
134
|
+
server(:default).with_sql_first(insert_select_sql(h))
|
135
|
+
end
|
136
|
+
def insert_select_sql(*v)
|
137
|
+
"#{insert_sql(*v)} RETURNING #{(opts[:returning] && !opts[:returning].empty?) ? opts[:returning].map{|c| literal(c)}.join(', ') : '*'}"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
@c.new(:name=>'foo').set_server(:read_only).save.must_equal @c.load(:id=>1, :name=>'foo', :i => 2)
|
141
|
+
@db.sqls.must_equal ["INSERT INTO people (name) VALUES ('foo') RETURNING #{@columns} -- read_only"]
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should work correctly when subclassing" do
|
145
|
+
c = Class.new(@c)
|
146
|
+
c[1].must_equal c.load(:id=>1, :name=>'foo', :i=>2)
|
147
|
+
@db.sqls.must_equal ["SELECT id, name, i FROM people WHERE (id = 1) LIMIT 1 -- read_only"]
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should correctly handle without schema type when placeholder type specifiers are required" do
|
151
|
+
@c.dataset = @ds.with_extend{def requires_placeholder_type_specifiers?; true end}
|
87
152
|
@c[1].must_equal @p
|
88
153
|
@db.sqls.must_equal ["SELECT id, name, i FROM people WHERE (id = 1) LIMIT 1 -- read_only"]
|
89
154
|
end
|
90
155
|
|
91
|
-
it "should correctly handle with schema type" do
|
92
|
-
@c.
|
93
|
-
|
94
|
-
def
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
156
|
+
it "should correctly handle with schema type when placeholder type specifiers are required" do
|
157
|
+
@c.dataset = @ds.with_extend do
|
158
|
+
def requires_placeholder_type_specifiers?; true end
|
159
|
+
def prepare(*)
|
160
|
+
super.with_extend do
|
161
|
+
def literal_symbol_append(sql, v)
|
162
|
+
if @opts[:bind_vars] && (match = /\A\$(.*)\z/.match(v.to_s))
|
163
|
+
s = match[1].split('__')[0].to_sym
|
164
|
+
if prepared_arg?(s)
|
165
|
+
literal_append(sql, prepared_arg(s))
|
166
|
+
else
|
167
|
+
sql << v.to_s
|
168
|
+
end
|
169
|
+
else
|
170
|
+
super
|
171
|
+
end
|
101
172
|
end
|
102
|
-
else
|
103
|
-
super
|
104
173
|
end
|
105
174
|
end
|
106
175
|
end
|
176
|
+
@c.db_schema[:id][:type] = :integer
|
107
177
|
@c[1].must_equal @p
|
108
178
|
@db.sqls.must_equal ["SELECT id, name, i FROM people WHERE (id = 1) LIMIT 1 -- read_only"]
|
109
179
|
end
|
110
180
|
end
|
181
|
+
|
182
|
+
describe "when #use_prepared_statements_for? returns false" do
|
183
|
+
before do
|
184
|
+
@columns = "*"
|
185
|
+
@c.class_eval do
|
186
|
+
def self.use_prepared_statements_for_pk_lookup?; false end
|
187
|
+
def use_prepared_statements_for?(type) false end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
include prepared_statements_spec
|
192
|
+
|
193
|
+
it "should correctly create instance" do
|
194
|
+
@c.create(:name=>'foo').must_equal @c.load(:id=>1, :name=>'foo', :i => 2)
|
195
|
+
@db.sqls.must_equal ["INSERT INTO people (name) VALUES ('foo')", "SELECT #{@columns} FROM people WHERE id = 1"]
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should correctly lookup by primary key" do
|
199
|
+
@c[1].must_equal @p
|
200
|
+
@db.sqls.must_equal ["SELECT * FROM people WHERE id = 1 -- read_only"]
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should correctly delete instance" do
|
204
|
+
@p.destroy.must_equal @p
|
205
|
+
@db.sqls.must_equal ["DELETE FROM people WHERE id = 1"]
|
206
|
+
end
|
207
|
+
end
|
111
208
|
end
|
@@ -28,4 +28,11 @@ describe "prepared_statements_with_pk plugin" do
|
|
28
28
|
@c.dataset.filter{id > 2}[1].must_equal @p
|
29
29
|
@c.db.sqls.must_equal ["SELECT * FROM people WHERE ((id > 2) AND (people.id = 1)) LIMIT 1 -- read_only"]
|
30
30
|
end
|
31
|
+
|
32
|
+
it "should respect explicitly set server" do
|
33
|
+
@c.dataset.filter(:name=>'foo')[1].must_equal @p
|
34
|
+
@c.db.sqls.must_equal ["SELECT * FROM people WHERE ((name = 'foo') AND (people.id = 1)) LIMIT 1 -- read_only"]
|
35
|
+
@c.dataset.server(:default).filter(:name=>'foo')[1].must_equal @p
|
36
|
+
@c.db.sqls.must_equal ["SELECT * FROM people WHERE ((name = 'foo') AND (people.id = 1)) LIMIT 1"]
|
37
|
+
end
|
31
38
|
end
|
@@ -108,7 +108,7 @@ describe "Serialization plugin" do
|
|
108
108
|
DB.sqls.must_equal ["SELECT * FROM items LIMIT 1",
|
109
109
|
"UPDATE items SET abc = '#{23.to_yaml}' WHERE (id = 1)",
|
110
110
|
"INSERT INTO items (abc) VALUES ('#{[1, 2, 3].to_yaml}')",
|
111
|
-
"SELECT * FROM items WHERE
|
111
|
+
"SELECT * FROM items WHERE id = 10"]
|
112
112
|
end
|
113
113
|
|
114
114
|
it "should translate values to and from marshal serialization format using accessor methods" do
|
@@ -128,7 +128,7 @@ describe "Serialization plugin" do
|
|
128
128
|
DB.sqls.must_equal ["SELECT * FROM items LIMIT 1",
|
129
129
|
"UPDATE items SET abc = '#{[Marshal.dump(23)].pack('m')}' WHERE (id = 1)",
|
130
130
|
"INSERT INTO items (abc) VALUES ('#{[Marshal.dump([1, 2, 3])].pack('m')}')",
|
131
|
-
"SELECT * FROM items WHERE
|
131
|
+
"SELECT * FROM items WHERE id = 10"]
|
132
132
|
end
|
133
133
|
|
134
134
|
it "should handle old non-base-64 encoded marshal serialization format" do
|
@@ -169,7 +169,7 @@ describe "Serialization plugin" do
|
|
169
169
|
DB.sqls.must_equal ["SELECT * FROM items LIMIT 1",
|
170
170
|
"UPDATE items SET abc = '#{[23].to_json}' WHERE (id = 1)",
|
171
171
|
"INSERT INTO items (abc) VALUES ('#{[1,2,3].to_json}')",
|
172
|
-
"SELECT * FROM items WHERE
|
172
|
+
"SELECT * FROM items WHERE id = 10"]
|
173
173
|
end
|
174
174
|
|
175
175
|
it "should translate values to and from arbitrary callables using accessor methods" do
|
@@ -190,7 +190,7 @@ describe "Serialization plugin" do
|
|
190
190
|
DB.sqls.must_equal ["SELECT * FROM items LIMIT 1",
|
191
191
|
"UPDATE items SET abc = 'oof' WHERE (id = 1)",
|
192
192
|
"INSERT INTO items (abc) VALUES ('rab')",
|
193
|
-
"SELECT * FROM items WHERE
|
193
|
+
"SELECT * FROM items WHERE id = 10"]
|
194
194
|
end
|
195
195
|
|
196
196
|
it "should handle registration of custom serializer/deserializer pairs" do
|
@@ -213,7 +213,7 @@ describe "Serialization plugin" do
|
|
213
213
|
DB.sqls.must_equal ["SELECT * FROM items LIMIT 1",
|
214
214
|
"UPDATE items SET abc = 'oof' WHERE (id = 1)",
|
215
215
|
"INSERT INTO items (abc) VALUES ('rab')",
|
216
|
-
"SELECT * FROM items WHERE
|
216
|
+
"SELECT * FROM items WHERE id = 10"]
|
217
217
|
end
|
218
218
|
|
219
219
|
it "should copy serialization formats and columns to subclasses" do
|
@@ -233,7 +233,7 @@ describe "Serialization plugin" do
|
|
233
233
|
DB.sqls.must_equal ["SELECT * FROM items LIMIT 1",
|
234
234
|
"UPDATE items SET abc = '#{23.to_yaml}' WHERE (id = 1)",
|
235
235
|
"INSERT INTO items (abc) VALUES ('#{[1, 2, 3].to_yaml}')",
|
236
|
-
"SELECT * FROM items WHERE
|
236
|
+
"SELECT * FROM items WHERE id = 10"]
|
237
237
|
end
|
238
238
|
|
239
239
|
it "should clear the deserialized columns when refreshing" do
|